Restructure libxutil to prepare for adding vnets.
Move common files from xfrd into libxutil.
40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile
40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c
40e03332KYz7o1bn2MG_KPbBlyoIMA tools/libxutil/allocate.h
+41a216cav5JJbtDQnusfuMa_1x_Xpw tools/libxutil/debug.h
+40e9808eyjiahG5uF6AMelNVujBzCg tools/libxutil/enum.c
+40e9808eZpbdn9q2KSSMGCNvY_ZgpQ tools/libxutil/enum.h
40e03332p5Dc_owJQRuN72ymJZddFQ tools/libxutil/file_stream.c
40e03332jWfB2viAhLSkq1WK0r_iDQ tools/libxutil/file_stream.h
40e03332rUjNMGg11n2rN6V4DCrvOg tools/libxutil/gzip_stream.c
40e033321O5Qg22haLoq5lpmk4tooQ tools/libxutil/gzip_stream.h
+40e9808easXCzzAZQodEfKAhgUXSPA tools/libxutil/hash_table.c
+40e9808e94BNXIVVKBFHC3rnkvwtJg tools/libxutil/hash_table.h
40e03332ihnBGzHykVwZnFmkAppb4g tools/libxutil/iostream.c
40e03332UGwbLR4wsw4ft14p0Yw5pg tools/libxutil/iostream.h
40e0333245DLDzJemeSVBLuutHtzEQ tools/libxutil/kernel_stream.c
40e03332aK0GkgpDdc-PVTkWKTeOBg tools/libxutil/kernel_stream.h
+40e9808epW9iHcLXuO3QfUfLzB7onw tools/libxutil/lexis.c
+40e9808egccMhCizayQRGtpBA3L5MQ tools/libxutil/lexis.h
+41a216caM4z39Fzjb91rv9Ed_4By1A tools/libxutil/socket_stream.c
+41a216caqinvF1I5FQMHA4HTRz8MSA tools/libxutil/socket_stream.h
40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/libxutil/string_stream.c
40e03332-VtK6_OZa1vMHXFil8uq6w tools/libxutil/string_stream.h
+40e9808e5_PLdodqVOSx0b4T_f5aeg tools/libxutil/sxpr.c
+40e9808e0O4sHZtkDv5hlSqjYcdQAQ tools/libxutil/sxpr.h
+40ec1cc6SIiGbynOi-1NtPesOlzF-Q tools/libxutil/sxpr_parser.c
+40ec1cc6wpvvGxZiq4EFvNOcw0tUFg tools/libxutil/sxpr_parser.h
40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/libxutil/sys_net.c
40e03332lQHvQHw4Rh7VsT1_sui29A tools/libxutil/sys_net.h
40e033321smklZd7bDSdWvQCeIshtg tools/libxutil/sys_string.c
40e03332h5V611rRWURRLqb1Ekatxg tools/libxutil/sys_string.h
+41a216cayFe2FQroFuzvNPw1AvNiqQ tools/libxutil/util.c
+41a216ca7mgVSnCBHPCLkGOIqPS1CQ tools/libxutil/util.h
3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen
3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
40e9808eysqT4VNDlJFqsZB2rdg4Qw tools/xfrd/connection.c
40e9808eyXfJUi4E0C3WSgrEXqQ1sQ tools/xfrd/connection.h
40e9808eULGwffNOE4kBrAfZ9YAVMA tools/xfrd/debug.h
-40e9808eyjiahG5uF6AMelNVujBzCg tools/xfrd/enum.c
-40e9808eZpbdn9q2KSSMGCNvY_ZgpQ tools/xfrd/enum.h
-40e9808easXCzzAZQodEfKAhgUXSPA tools/xfrd/hash_table.c
-40e9808e94BNXIVVKBFHC3rnkvwtJg tools/xfrd/hash_table.h
411b5139tfKZfWs1LQHmwDR_wjKoxQ tools/xfrd/http.h
-40e9808epW9iHcLXuO3QfUfLzB7onw tools/xfrd/lexis.c
-40e9808egccMhCizayQRGtpBA3L5MQ tools/xfrd/lexis.h
40e9808ePADCSKL1YgGCt2TbYPnYkw tools/xfrd/lzi_stream.c
40e9808eDNAdpF71o5teYb9DTT-PRw tools/xfrd/lzi_stream.h
40e9808eQxi0EzTcPJtosrzxEIjA-Q tools/xfrd/marshal.c
40e9808etg13xfRm0Lqd8vY-jHOoTg tools/xfrd/marshal.h
40e9808eCsmywryb036TdtRMJHDMmQ tools/xfrd/select.c
40e9808e99OcM547cKMTfmCVSoWVAw tools/xfrd/select.h
-40e9808e5_PLdodqVOSx0b4T_f5aeg tools/xfrd/sxpr.c
-40e9808e0O4sHZtkDv5hlSqjYcdQAQ tools/xfrd/sxpr.h
-40ec1cc6SIiGbynOi-1NtPesOlzF-Q tools/xfrd/sxpr_parser.c
-40ec1cc6wpvvGxZiq4EFvNOcw0tUFg tools/xfrd/sxpr_parser.h
40e9808eF3NVldqRNS5IHM8gbFAvpw tools/xfrd/xdr.c
40e9808ezXzoRHm7pybXU69NtnjimA tools/xfrd/xdr.h
40e9808edpUtf4bJ8IbqClPJj_OvbA tools/xfrd/xen_domain.c
LIB_SRCS :=
LIB_SRCS += allocate.c
+LIB_SRCS += enum.c
LIB_SRCS += file_stream.c
LIB_SRCS += gzip_stream.c
+LIB_SRCS += hash_table.c
LIB_SRCS += iostream.c
-#LIB_SRCS += sys_net.c
+LIB_SRCS += lexis.c
+LIB_SRCS += string_stream.c
+LIB_SRCS += sxpr.c
+LIB_SRCS += sxpr_parser.c
+LIB_SRCS += sys_net.c
LIB_SRCS += sys_string.c
+LIB_SRCS += util.c
LIB_OBJS := $(LIB_SRCS:.c=.o)
LIB := $(LIB_NAME).so
LIB += $(LIB_NAME).so.$(MAJOR)
LIB += $(LIB_NAME).so.$(MAJOR).$(MINOR)
+LIB += $(LIB_NAME).a
all: check-for-zlib
$(MAKE) $(LIB)
$(LIB_NAME).so.$(MAJOR).$(MINOR): $(LIB_OBJS)
$(CC) -Wl,-soname -Wl,$(LIB_NAME).so.$(MAJOR) -shared -o $@ $^
+$(LIB_NAME).a: $(LIB_OBJS)
+ $(AR) rc $@ $^
+
check-for-zlib:
@if [ ! -e /usr/include/zlib.h ]; then \
echo "***********************************************************"; \
--- /dev/null
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _XUTIL_DEBUG_H_
+#define _XUTIL_DEBUG_H_
+
+#ifndef MODULE_NAME
+#define MODULE_NAME ""
+#endif
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef DEBUG
+
+#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+
+#else
+
+#define dprintf(fmt, args...) do {} while(0)
+#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args)
+#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args)
+#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args)
+
+#endif
+
+#else
+
+#include <stdio.h>
+
+#ifdef DEBUG
+
+#define dprintf(fmt, args...) fprintf(stdout, "%d [DBG] " MODULE_NAME ">%s" fmt, getpid(), __FUNCTION__, ##args)
+#define wprintf(fmt, args...) fprintf(stderr, "%d [WRN] " MODULE_NAME ">%s" fmt, getpid(),__FUNCTION__, ##args)
+#define iprintf(fmt, args...) fprintf(stderr, "%d [INF] " MODULE_NAME ">%s" fmt, getpid(),__FUNCTION__, ##args)
+#define eprintf(fmt, args...) fprintf(stderr, "%d [ERR] " MODULE_NAME ">%s" fmt, getpid(),__FUNCTION__, ##args)
+
+#else
+
+#define dprintf(fmt, args...) do {} while(0)
+#define wprintf(fmt, args...) fprintf(stderr, "%d [WRN] " MODULE_NAME fmt, getpid(), ##args)
+#define iprintf(fmt, args...) fprintf(stderr, "%d [INF] " MODULE_NAME fmt, getpid(), ##args)
+#define eprintf(fmt, args...) fprintf(stderr, "%d [ERR] " MODULE_NAME fmt, getpid(), ##args)
+
+#endif
+
+#endif
+
+/** Print format for an IP address.
+ * See NIPQUAD(), HIPQUAD()
+ */
+#define IPFMT "%u.%u.%u.%u"
+
+#endif /* ! _XUTIL_DEBUG_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef __KERNEL__
+#include <linux/errno.h>
+#else
+#include <errno.h>
+#endif
+
+#include "sys_string.h"
+#include "enum.h"
+
+/** Map an enum name to its value using a table.
+ *
+ * @param name enum name
+ * @param defs enum definitions
+ * @return enum value or -1 if not known
+ */
+int enum_name_to_val(char *name, EnumDef *defs){
+ int val = -1;
+ for(; defs->name; defs++){
+ if(!strcmp(defs->name, name)){
+ val = defs->val;
+ break;
+ }
+ }
+ return val;
+}
+
+/** Map an enum value to its name using a table.
+ *
+ * @param val enum value
+ * @param defs enum definitions
+ * @param defs_n number of definitions
+ * @return enum name or NULL if not known
+ */
+char *enum_val_to_name(int val, EnumDef *defs){
+ char *name = NULL;
+ for(; defs->name; defs++){
+ if(val == defs->val){
+ name = defs->name;
+ break;
+ }
+ }
+ return name;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XUTIL_ENUM_H_
+#define _XUTIL_ENUM_H_
+
+/** Mapping of an enum value to a name. */
+typedef struct EnumDef {
+ int val;
+ char *name;
+} EnumDef;
+
+extern int enum_name_to_val(char *name, EnumDef *defs);
+extern char *enum_val_to_name(int val, EnumDef *defs);
+
+#endif /* _XUTIL_ENUM_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef __KERNEL__
+# include <linux/config.h>
+# include <linux/module.h>
+# include <linux/kernel.h>
+# include <linux/errno.h>
+#else
+# include <errno.h>
+# include <stddef.h>
+#endif
+
+//#include <limits.h>
+
+#include "allocate.h"
+#include "hash_table.h"
+
+/** @file
+ * Base support for hashtables.
+ *
+ * Hash codes are reduced modulo the number of buckets to index tables,
+ * so there is no need for hash functions to limit the range of hashcodes.
+ * In fact it is assumed that hashcodes do not change when the number of
+ * buckets in the table changes.
+ */
+
+/*==========================================================================*/
+/** Number of bits in half a word. */
+//#if __WORDSIZE == 64
+//#define HALF_WORD_BITS 32
+//#else
+#define HALF_WORD_BITS 16
+//#endif
+
+/** Mask for lo half of a word. On 32-bit this is
+ * (1<<16) - 1 = 65535 = 0xffff
+ * It's 4294967295 = 0xffffffff on 64-bit.
+ */
+#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1)
+
+/** Get the lo half of a word. */
+#define LO_HALF(x) ((x) & LO_HALF_MASK)
+
+/** Get the hi half of a word. */
+#define HI_HALF(x) ((x) >> HALF_WORD_BITS)
+
+/** Do a full hash on both inputs, using DES-style non-linear scrambling.
+ * Both inputs are replaced with the results of the hash.
+ *
+ * @param pleft input/output word
+ * @param pright input/output word
+ */
+void pseudo_des(unsigned long *pleft, unsigned long *pright){
+ // Bit-rich mixing constant.
+ static const unsigned long a_mixer[] = {
+ 0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, };
+
+ // Bit-rich mixing constant.
+ static const unsigned long b_mixer[] = {
+ 0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, };
+
+ // Number of iterations - must be 2 or 4.
+ static const int ncycle = 4;
+ //static const int ncycle = 2;
+
+ unsigned long left = *pleft, right = *pright;
+ unsigned long v, v_hi, v_lo;
+ int i;
+
+ for(i=0; i<ncycle; i++){
+ // Flip some bits in right to get v.
+ v = right;
+ v ^= a_mixer[i];
+ // Get lo and hi halves of v.
+ v_lo = LO_HALF(v);
+ v_hi = HI_HALF(v);
+ // Non-linear mix of the halves of v.
+ v = ((v_lo * v_lo) + ~(v_hi * v_hi));
+ // Swap the halves of v.
+ v = (HI_HALF(v) | (LO_HALF(v) << HALF_WORD_BITS));
+ // Flip some bits.
+ v ^= b_mixer[i];
+ // More non-linear mixing.
+ v += (v_lo * v_hi);
+ v ^= left;
+ left = right;
+ right = v;
+ }
+ *pleft = left;
+ *pright = right;
+}
+
+/** Hash a string.
+ *
+ * @param s input to hash
+ * @return hashcode
+ */
+Hashcode hash_string(char *s){
+ Hashcode h = 0;
+ if(s){
+ for( ; *s; s++){
+ h = hash_2ul(h, *s);
+ }
+ }
+ return h;
+}
+
+/** Get the bucket for a hashcode in a hash table.
+ *
+ * @param table to get bucket from
+ * @param hashcode to get bucket for
+ * @return bucket
+ */
+inline HTBucket * get_bucket(HashTable *table, Hashcode hashcode){
+ return table->buckets + (hashcode % table->buckets_n);
+}
+
+/** Initialize a hash table.
+ * Can be safely called more than once.
+ *
+ * @param table to initialize
+ */
+void HashTable_init(HashTable *table){
+ int i;
+
+ if(!table->init_done){
+ table->init_done = 1;
+ table->next_id = 0;
+ for(i=0; i<table->buckets_n; i++){
+ HTBucket *bucket = get_bucket(table, i);
+ bucket->head = 0;
+ bucket->count = 0;
+ }
+ table->entry_count = 0;
+ }
+}
+
+/** Allocate a new hashtable.
+ * If the number of buckets is not positive the default is used.
+ * The number of buckets should usually be prime.
+ *
+ * @param buckets_n number of buckets
+ * @return new hashtable or null
+ */
+HashTable *HashTable_new(int buckets_n){
+ HashTable *z = ALLOCATE(HashTable);
+ if(!z) goto exit;
+ if(buckets_n <= 0){
+ buckets_n = HT_BUCKETS_N;
+ }
+ z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
+ if(!z->buckets){
+ deallocate(z);
+ z = 0;
+ goto exit;
+ }
+ z->buckets_n = buckets_n;
+ HashTable_init(z);
+ exit:
+ return z;
+}
+
+/** Free a hashtable.
+ * Any entries are removed and freed.
+ *
+ * @param h hashtable (ignored if null)
+ */
+void HashTable_free(HashTable *h){
+ if(h){
+ HashTable_clear(h);
+ deallocate(h->buckets);
+ deallocate(h);
+ }
+}
+
+/** Push an entry on the list in the bucket for a given hashcode.
+ *
+ * @param table to add entry to
+ * @param hashcode for the entry
+ * @param entry to add
+ */
+static inline void push_on_bucket(HashTable *table, Hashcode hashcode,
+ HTEntry *entry){
+ HTBucket *bucket;
+ HTEntry *old_head;
+
+ bucket = get_bucket(table, hashcode);
+ old_head = bucket->head;
+ bucket->count++;
+ bucket->head = entry;
+ entry->next = old_head;
+}
+
+/** Change the number of buckets in a hashtable.
+ * No-op if the number of buckets is not positive.
+ * Existing entries are reallocated to buckets based on their hashcodes.
+ * The table is unmodified if the number of buckets cannot be changed.
+ *
+ * @param table hashtable
+ * @param buckets_n new number of buckets
+ * @return 0 on success, error code otherwise
+ */
+int HashTable_set_buckets_n(HashTable *table, int buckets_n){
+ int err = 0;
+ HTBucket *old_buckets = table->buckets;
+ int old_buckets_n = table->buckets_n;
+ int i;
+
+ if(buckets_n <= 0){
+ err = -EINVAL;
+ goto exit;
+ }
+ table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
+ if(!table->buckets){
+ err = -ENOMEM;
+ table->buckets = old_buckets;
+ goto exit;
+ }
+ table->buckets_n = buckets_n;
+ for(i=0; i<old_buckets_n; i++){
+ HTBucket *bucket = old_buckets + i;
+ HTEntry *entry, *next;
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ push_on_bucket(table, entry->hashcode, entry);
+ }
+ }
+ deallocate(old_buckets);
+ exit:
+ return err;
+}
+
+/** Adjust the number of buckets so the table is neither too full nor too empty.
+ * The table is unmodified if adjusting fails.
+ *
+ * @param table hash table
+ * @param buckets_min minimum number of buckets (use default if 0 or negative)
+ * @return 0 on success, error code otherwise
+ */
+int HashTable_adjust(HashTable *table, int buckets_min){
+ int buckets_n = 0;
+ int err = 0;
+ if(buckets_min <= 0) buckets_min = HT_BUCKETS_N;
+ if(table->entry_count >= table->buckets_n){
+ // The table is dense - expand it.
+ buckets_n = 2 * table->buckets_n;
+ } else if((table->buckets_n > buckets_min) &&
+ (4 * table->entry_count < table->buckets_n)){
+ // The table is more than minimum size and sparse - shrink it.
+ buckets_n = 2 * table->entry_count;
+ if(buckets_n < buckets_min) buckets_n = buckets_min;
+ }
+ if(buckets_n){
+ err = HashTable_set_buckets_n(table, buckets_n);
+ }
+ return err;
+}
+
+/** Allocate a new entry for a given value.
+ *
+ * @param value to put in the entry
+ * @return entry, or 0 on failure
+ */
+HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){
+ HTEntry *z = ALLOCATE(HTEntry);
+ if(z){
+ z->hashcode = hashcode;
+ z->key = key;
+ z->value = value;
+ }
+ return z;
+}
+
+/** Free an entry.
+ *
+ * @param z entry to free
+ */
+inline void HTEntry_free(HTEntry *z){
+ if(z){
+ deallocate(z);
+ }
+}
+
+/** Free an entry in a hashtable.
+ * The table's entry_free_fn is used is defined, otherwise
+ * the HTEntry itself is freed.
+ *
+ * @param table hashtable
+ * @param entry to free
+ */
+inline void HashTable_free_entry(HashTable *table, HTEntry *entry){
+ if(!entry)return;
+ if(table && table->entry_free_fn){
+ table->entry_free_fn(table, entry);
+ } else {
+ HTEntry_free(entry);
+ }
+}
+
+/** Get the first entry satisfying a test from the bucket for the
+ * given hashcode.
+ *
+ * @param table to look in
+ * @param hashcode indicates the bucket
+ * @param test_fn test to apply to elements
+ * @param arg first argument to calls to test_fn
+ * @return entry found, or 0
+ */
+inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
+ TableTestFn *test_fn, TableArg arg){
+ HTBucket *bucket;
+ HTEntry *entry = 0;
+ HTEntry *next;
+
+ bucket = get_bucket(table, hashcode);
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ if(test_fn(arg, table, entry)){
+ break;
+ }
+ }
+ return entry;
+}
+
+/** Test hashtable keys for equality.
+ * Uses the table's key_equal_fn if defined, otherwise pointer equality.
+ *
+ * @param key1 key to compare
+ * @param key2 key to compare
+ * @return 1 if equal, 0 otherwise
+ */
+inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
+ return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2);
+}
+
+/** Compute the hashcode of a hashtable key.
+ * The table's key_hash_fn is used if defined, otherwise the address of
+ * the key is hashed.
+ *
+ * @param table hashtable
+ * @param key to hash
+ * @return hashcode
+ */
+inline Hashcode HashTable_key_hash(HashTable *table, void *key){
+ return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key));
+}
+
+/** Test if an entry has a given key.
+ *
+ * @param arg containing key to test for
+ * @param table the entry is in
+ * @param entry to test
+ * @return 1 if the entry has the key, 0 otherwise
+ */
+static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){
+ return HashTable_key_equal(table, arg.ptr, entry->key);
+}
+
+/** Get an entry with a given key.
+ *
+ * @param table to search
+ * @param key to look for
+ * @return entry if found, null otherwise
+ */
+#if 0
+inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
+ TableArg arg = { ptr: key };
+ return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg);
+}
+#else
+inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
+ Hashcode hashcode;
+ HTBucket *bucket;
+ HTEntry *entry = 0;
+ HTEntry *next;
+
+ hashcode = HashTable_key_hash(table, key);
+ bucket = get_bucket(table, hashcode);
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ if(HashTable_key_equal(table, key, entry->key)){
+ break;
+ }
+ }
+ return entry;
+}
+#endif
+
+/** Get the value of an entry with a given key.
+ *
+ * @param table to search
+ * @param key to look for
+ * @return value if an entry was found, null otherwise
+ */
+inline void * HashTable_get(HashTable *table, void *key){
+ HTEntry *entry = HashTable_get_entry(table, key);
+ return (entry ? entry->value : 0);
+}
+
+/** Print the buckets in a table.
+ *
+ * @param table to print
+ */
+void show_buckets(HashTable *table, IOStream *io){
+ int i,j ;
+ IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n);
+ for(i=0; i<table->buckets_n; i++){
+ if(0 || table->buckets[i].count>0){
+ IOStream_print(io, "bucket %3d %3d %10p ", i,
+ table->buckets[i].count,
+ table->buckets[i].head);
+ for(j = table->buckets[i].count; j>0; j--){
+ IOStream_print(io, "+");
+ }
+ IOStream_print(io, "\n");
+ }
+ }
+ HashTable_print(table, io);
+}
+
+/** Print an entry in a table.
+ *
+ * @param entry to print
+ * @param arg a pointer to an IOStream to print to
+ * @return 0
+ */
+static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){
+ IOStream *io = (IOStream*)arg.ptr;
+ IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n",
+ entry->hashcode % table->buckets_n,
+ entry->hashcode,
+ entry->index,
+ entry, entry->key, entry->value);
+ return 0;
+}
+
+/** Print a hash table.
+ *
+ * @param table to print
+ */
+void HashTable_print(HashTable *table, IOStream *io){
+ IOStream_print(io, "{\n");
+ HashTable_map(table, print_entry, (TableArg){ ptr: io });
+ IOStream_print(io, "}\n");
+}
+/*==========================================================================*/
+
+/** Get the next entry id to use for a table.
+ *
+ * @param table hash table
+ * @return non-zero entry id
+ */
+static inline unsigned long get_next_id(HashTable *table){
+ unsigned long id;
+
+ if(table->next_id == 0){
+ table->next_id = 1;
+ }
+ id = table->next_id++;
+ return id;
+}
+
+/** Add an entry to the bucket for the
+ * given hashcode.
+ *
+ * @param table to insert in
+ * @param hashcode indicates the bucket
+ * @param key to add an entry for
+ * @param value to add an entry for
+ * @return entry on success, 0 on failure
+ */
+inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){
+ HTEntry *entry = HTEntry_new(hashcode, key, value);
+ if(entry){
+ entry->index = get_next_id(table);
+ push_on_bucket(table, hashcode, entry);
+ table->entry_count++;
+ }
+ return entry;
+}
+
+/** Move the front entry for a bucket to the correct point in the bucket order as
+ * defined by the order function. If this is called every time a new entry is added
+ * the bucket will be maintained in sorted order.
+ *
+ * @param table to modify
+ * @param hashcode indicates the bucket
+ * @param order entry comparison function
+ * @return 0 if an entry was moved, 1 if not
+ */
+int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){
+ HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL;
+ HTBucket *bucket;
+ int err = 1;
+
+ bucket = get_bucket(table, hashcode);
+ new_entry = bucket->head;
+ if(!new_entry || !new_entry->next) goto exit;
+ for(entry = new_entry->next; entry; prev = entry, entry = entry->next){
+ if(order(new_entry, entry) <= 0) break;
+ }
+ if(prev){
+ err = 0;
+ bucket->head = new_entry->next;
+ new_entry->next = entry;
+ prev->next = new_entry;
+ }
+ exit:
+ return err;
+}
+
+/** Add an entry to a hashtable.
+ * The entry is added to the bucket for its key's hashcode.
+ *
+ * @param table to insert in
+ * @param key to add an entry for
+ * @param value to add an entry for
+ * @return entry on success, 0 on failure
+ */
+inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){
+ return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);
+}
+
+
+/** Remove entries satisfying a test from the bucket for the
+ * given hashcode.
+ *
+ * @param table to remove from
+ * @param hashcode indicates the bucket
+ * @param test_fn test to apply to elements
+ * @param arg first argument to calls to test_fn
+ * @return number of entries removed
+ */
+inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
+ TableTestFn *test_fn, TableArg arg){
+ HTBucket *bucket;
+ HTEntry *entry, *prev = 0, *next;
+ int removed_count = 0;
+
+ bucket = get_bucket(table, hashcode);
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ if(test_fn(arg, table, entry)){
+ if(prev){
+ prev->next = next;
+ } else {
+ bucket->head = next;
+ }
+ bucket->count--;
+ table->entry_count--;
+ removed_count++;
+ HashTable_free_entry(table, entry);
+ entry = 0;
+ }
+ prev = entry;
+ }
+ return removed_count;
+}
+
+/** Remove entries with a given key.
+ *
+ * @param table to remove from
+ * @param key of entries to remove
+ * @return number of entries removed
+ */
+inline int HashTable_remove(HashTable *table, void *key){
+#if 1
+ Hashcode hashcode;
+ HTBucket *bucket;
+ HTEntry *entry, *prev = 0, *next;
+ int removed_count = 0;
+
+ hashcode = HashTable_key_hash(table, key);
+ bucket = get_bucket(table, hashcode);
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ if(HashTable_key_equal(table, key, entry->key)){
+ if(prev){
+ prev->next = next;
+ } else {
+ bucket->head = next;
+ }
+ bucket->count--;
+ table->entry_count--;
+ removed_count++;
+ HashTable_free_entry(table, entry);
+ entry = 0;
+ }
+ prev = entry;
+ }
+ return removed_count;
+#else
+ return HashTable_remove_entry(table, HashTable_key_hash(table, key),
+ has_key, (TableArg){ ptr: key});
+#endif
+}
+
+/** Remove (and free) all the entries in a bucket.
+ *
+ * @param bucket to clear
+ */
+static inline void bucket_clear(HashTable *table, HTBucket *bucket){
+ HTEntry *entry, *next;
+
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ HashTable_free_entry(table, entry);
+ }
+ bucket->head = 0;
+ table->entry_count -= bucket->count;
+ bucket->count = 0;
+}
+
+/** Remove (and free) all the entries in a table.
+ *
+ * @param table to clear
+ */
+void HashTable_clear(HashTable *table){
+ int i, n = table->buckets_n;
+
+ for(i=0; i<n; i++){
+ bucket_clear(table, table->buckets + i);
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XUTIL_HASH_TABLE_H_
+#define _XUTIL_HASH_TABLE_H_
+
+#include "iostream.h"
+
+typedef unsigned long Hashcode;
+
+/** Type used to pass parameters to table functions. */
+typedef union TableArg {
+ unsigned long ul;
+ void *ptr;
+} TableArg;
+
+/** An entry in a bucket list. */
+typedef struct HTEntry {
+ /** Hashcode of the entry's key. */
+ Hashcode hashcode;
+ /** Identifier for this entry in the table. */
+ int index;
+ /** The key for this entry. */
+ void *key;
+ /** The value in this entry. */
+ void *value;
+ /** The next entry in the list. */
+ struct HTEntry *next;
+} HTEntry;
+
+/** A bucket in a rule table. */
+typedef struct HTBucket {
+ /** Number of entries in the bucket. */
+ int count;
+ /** First entry in the bucket (may be null). */
+ HTEntry *head;
+} HTBucket;
+
+/** Default number of buckets in a hash table.
+ * You want enough buckets so the lists in the buckets will typically be short.
+ * It's a good idea if this is prime, since that will help to spread hashcodes
+ * around the table.
+ */
+//#define HT_BUCKETS_N 1
+//#define HT_BUCKETS_N 3
+//#define HT_BUCKETS_N 7
+//#define HT_BUCKETS_N 17
+//#define HT_BUCKETS_N 97
+//#define HT_BUCKETS_N 211
+//#define HT_BUCKETS_N 401
+#define HT_BUCKETS_N 1021
+
+typedef struct HashTable HashTable;
+
+/** Type for a function used to select table entries. */
+typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry);
+
+/** Type for a function to map over table entries. */
+typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry);
+
+/** Type for a function to free table entries. */
+typedef void TableFreeFn(HashTable *table, HTEntry *entry);
+
+/** Type for a function to hash table keys. */
+typedef Hashcode TableHashFn(void *key);
+
+/** Type for a function to test table keys for equality. */
+typedef int TableEqualFn(void *key1, void *key2);
+
+/** Type for a function to order table entries. */
+typedef int TableOrderFn(HTEntry *e1, HTEntry *e2);
+
+/** General hash table.
+ * A hash table with a list in each bucket.
+ * Functions can be supplied for freeing entries, hashing keys, and comparing keys.
+ * These all default to 0, when default behaviour treating keys as integers is used.
+ */
+struct HashTable {
+ /** Flag indicating whether the table has been initialised. */
+ int init_done;
+ /** Next value for the id field in inserted rules. */
+ unsigned long next_id;
+ /** Number of buckets in the bucket array. */
+ int buckets_n;
+ /** Array of buckets, each with its own list. */
+ HTBucket *buckets;
+ /** Number of entries in the table. */
+ int entry_count;
+ /** Function to free keys and values in entries. */
+ TableFreeFn *entry_free_fn;
+ /** Function to hash keys. */
+ TableHashFn *key_hash_fn;
+ /** Function to compare keys for equality. */
+ TableEqualFn *key_equal_fn;
+ /** Place for the user of the table to hang extra data. */
+ void *user_data;
+};
+
+extern HashTable *HashTable_new(int bucket_n);
+extern void HashTable_free(HashTable *table);
+extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value);
+extern void HTEntry_free(HTEntry *entry);
+extern int HashTable_set_bucket_n(HashTable *table, int bucket_n);
+extern void HashTable_clear(HashTable *table);
+extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value);
+extern HTEntry * HashTable_get_entry(HashTable *table, void *key);
+extern HTEntry * HashTable_add(HashTable *table, void *key, void *value);
+extern void * HashTable_get(HashTable *table, void *key);
+extern int HashTable_remove(HashTable *table, void *key);
+extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
+ TableTestFn *test_fn, TableArg arg);
+extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
+ TableTestFn *test_fn, TableArg arg);
+//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg);
+extern void HashTable_print(HashTable *table, IOStream *out);
+extern int HashTable_set_buckets_n(HashTable *table, int buckets_n);
+extern int HashTable_adjust(HashTable *table, int buckets_min);
+extern void pseudo_des(unsigned long *pleft, unsigned long *pright);
+extern Hashcode hash_string(char *s);
+
+extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order);
+
+/** Control whether to use hashing based on DES or simple
+ * hashing. DES hashing is `more random' but much more expensive.
+ */
+#define HASH_PSEUDO_DES 0
+
+/** Hash a long using a quick and dirty linear congruential random number generator.
+ * See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator".
+ *
+ * @param a value to hash
+ * @return hashed input
+ */
+static inline unsigned long lcrng_hash(unsigned long a){
+ return (1664525L * a + 1013904223L);
+}
+
+/** Hash an unsigned long.
+ *
+ * @param a input to hash
+ * @return hashcode
+ */
+static inline Hashcode hash_ul(unsigned long a){
+#if HASH_PSEUDO_DES
+ unsigned long left = a;
+ unsigned long right = 0L;
+ pseudo_des(&left, &right);
+ return right;
+#else
+ a = lcrng_hash(a);
+ a = lcrng_hash(a);
+ return a;
+#endif
+}
+
+/** Hash two unsigned longs together.
+ *
+ * @param a input to hash
+ * @param b input to hash
+ * @return hashcode
+ */
+static inline Hashcode hash_2ul(unsigned long a, unsigned long b){
+#if HASH_PSEUDO_DES
+ unsigned long left = a;
+ unsigned long right = b;
+ pseudo_des(&left, &right);
+ return right;
+#else
+ a = lcrng_hash(a);
+ a ^= b;
+ a = lcrng_hash(a);
+ return a;
+#endif
+}
+
+/** Hash a hashcode and an unsigned long together.
+ *
+ * @param a input hashcode
+ * @param b input to hash
+ * @return hashcode
+ */
+static inline Hashcode hash_hul(Hashcode a, unsigned long b){
+#if HASH_PSEUDO_DES
+ unsigned long left = a;
+ unsigned long right = b;
+ pseudo_des(&left, &right);
+ return right;
+#else
+ a ^= b;
+ a = lcrng_hash(a);
+ return a;
+#endif
+}
+
+/** Macro to declare variables for HashTable_for_each() to use.
+ *
+ * @param entry variable that is set to entries in the table
+ */
+#define HashTable_for_decl(entry) \
+ HashTable *_var_table; \
+ HTBucket *_var_bucket; \
+ HTBucket *_var_end; \
+ HTEntry *_var_next; \
+ HTEntry *entry
+
+/** Macro to iterate over the entries in a hashtable.
+ * Must be in a scope where HashTable_for_decl() has been used to declare
+ * variables for it to use.
+ * The variable 'entry' is iterated over entries in the table.
+ * The code produced is syntactically a loop, so it must be followed by
+ * a loop body, typically some statements in braces:
+ * HashTable_for_each(entry, table){ ...loop body... }
+ *
+ * HashTable_for_each() and HashTable_for_decl() cannot be used for nested
+ * loops as variables will clash.
+ *
+ * @note The simplest way to code a direct loop over the entries in a hashtable
+ * is to use a loop over the buckets, with a nested loop over the entries
+ * in a bucket. Using this approach in a macro means the macro contains
+ * an opening brace, and calls to it must be followed by 2 braces!
+ * To avoid this the code has been restructured so that it is a for loop.
+ * So that statements could be used in the test expression of the for loop,
+ * we have used the gcc statement expression extension ({ ... }).
+ *
+ * @param entry variable to iterate over the entries
+ * @param table to iterate over (non-null)
+ */
+#define HashTable_for_each(entry, table) \
+ _var_table = table; \
+ _var_bucket = _var_table->buckets; \
+ _var_end = _var_bucket + _var_table->buckets_n; \
+ for(entry=0, _var_next=0; \
+ ({ if(_var_next){ \
+ entry = _var_next; \
+ _var_next = entry->next; \
+ } else { \
+ while(_var_bucket < _var_end){ \
+ entry = _var_bucket->head; \
+ _var_bucket++; \
+ if(entry){ \
+ _var_next = entry->next; \
+ break; \
+ } \
+ } \
+ }; \
+ entry; }); \
+ entry = _var_next )
+
+/** Map a function over the entries in a table.
+ * Mapping stops when the function returns a non-zero value.
+ * Uses the gcc statement expression extension ({ ... }).
+ *
+ * @param table to map over
+ * @param fn function to apply to entries
+ * @param arg first argument to call the function with
+ * @return 0 if fn always returned 0, first non-zero value otherwise
+ */
+#define HashTable_map(table, fn, arg) \
+ ({ HashTable_for_decl(_var_entry); \
+ TableArg _var_arg = arg; \
+ int _var_value = 0; \
+ HashTable_for_each(_var_entry, table){ \
+ if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \
+ } \
+ _var_value; })
+
+/** Cast x to the type for a key or value in a hash table.
+ * This avoids compiler warnings when using short integers
+ * as keys or values (especially on 64-bit platforms).
+ */
+#define HKEY(x) ((void*)(unsigned long)(x))
+
+/** Cast x from the type for a key or value in a hash table.
+ * to an unsigned long. This avoids compiler warnings when using
+ * short integers as keys or values (especially on 64-bit platforms).
+ */
+#define HVAL(x) ((unsigned long)(x))
+
+#endif /* !_XUTIL_HASH_TABLE_H_ */
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "iostream.h"
#include "sys_string.h"
-#ifndef _XC_LINUX_SAVE_H_
-#define _XC_LINUX_SAVE_H_
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XUTIL_IOSTREAM_H_
+#define _XUTIL_IOSTREAM_H_
#include <stdarg.h>
-#include <stdint.h>
-#include <stddef.h>
#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/types.h>
#include <linux/errno.h>
#else
#include <errno.h>
+#include <stdint.h>
+#include <stddef.h>
#endif
#include "allocate.h"
}
-#endif /* ! _XC_LINUX_SAVE_H_ */
+#endif /* ! _XUTIL_IOSTREAM_H_ */
char buf[BUF_N];
} KernelData;
-static int kernel_write(IOStream *s, const char *msg, int n);
+static int kernel_write(IOStream *s, const void *msg, size_t n);
static void kernel_free(IOStream *s);
static void kernel_stream_lock(IOStream *s);
static void kernel_stream_unlock(IOStream *s);
* @param args print arguments
* @return result of the print
*/
-static int kernel_write(IOStream *stream, const char *buf, int n){
+static int kernel_write(IOStream *stream, const void *buf, size_t n){
KernelData *kdata = get_kernel_data(stream);
int k;
k = kdata->buf_n - 1;
if(n < k) k = n;
memcpy(kdata->buf, buf, k);
- kdata->buf[k] = '\0'
+ kdata->buf[k] = '\0';
printk(kdata->buf);
return k;
}
KernelData *kdata;
if(io == &iokernel) return;
kdata = get_kernel_data(io);
- zero(kdata, sizeof(*kdata));
+ memset(kdata, 0, sizeof(*kdata));
deallocate(kdata);
}
#endif /* __KERNEL__ */
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * Lexical analysis.
+ */
+
+#include "sys_string.h"
+#include "lexis.h"
+#include <errno.h>
+
+/** Check if a value lies in a (closed) range.
+ *
+ * @param x value to test
+ * @param lo low end of the range
+ * @param hi high end of the range
+ * @return 1 if x is in the interval [lo, hi], 0 otherwise
+ */
+inline static int in_range(int x, int lo, int hi){
+ return (lo <= x) && (x <= hi);
+}
+
+/** Determine if a string is an (unsigned) decimal number.
+ *
+ * @param s pointer to characters to test
+ * @param n length of string
+ * @return 1 if s is a decimal number, 0 otherwise.
+ */
+int is_decimal_number(const char *s, int n){
+ int i;
+ if(n <= 0)return 0;
+ for(i = 0; i < n; i++){
+ if(!in_decimal_digit_class(s[i])) return 0;
+ }
+ return 1;
+}
+
+/** Determine if a string is a hex number.
+ * Hex numbers are 0, or start with 0x or 0X followed
+ * by a non-zero number of hex digits (0-9,a-f,A-F).
+ *
+ * @param s pointer to characters to test
+ * @param n length of string
+ * @return 1 if s is a hex number, 0 otherwise.
+ */
+int is_hex_number(const char *s, int n){
+ int i;
+ if(n <= 0) return 0;
+ if(n == 1){
+ return s[0]=='0';
+ }
+ if(n <= 3) return 0;
+ if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0;
+ for(i = 2; i < n; i++){
+ if(!in_hex_digit_class(s[i])) return 0;
+ }
+ return 1;
+}
+
+/** Test if a string matches a keyword.
+ * The comparison is case-insensitive.
+ * The comparison fails if either argument is null.
+ *
+ * @param s string
+ * @param k keyword
+ * @return 1 if they match, 0 otherwise
+ */
+int is_keyword(const char *s, const char *k){
+ return s && k && !strcasecmp(s, k);
+}
+
+/** Test if a string matches a character.
+ *
+ * @param s string
+ * @param c character (non-null)
+ * @return 1 if s contains exactly c, 0 otherwise
+ */
+int is_keychar(const char *s, char c){
+ return c && (s[0] == c) && !s[1];
+}
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XUTIL_LEXIS_H_
+#define _XUTIL_LEXIS_H_
+
+#include "sys_string.h"
+
+#ifdef __KERNEL__
+# include <linux/ctype.h>
+#else
+# include <ctype.h>
+#endif
+
+/** @file
+ * Lexical analysis.
+ */
+
+/** Class of characters treated as space. */
+#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
+
+/** Class of separator characters. */
+#define sep_class "{}()<>[]@!;"
+
+#define comment_class "#"
+
+/** Determine if a character is in a given class.
+ *
+ * @param c character to test
+ * @param s null-terminated string of characters in the class
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_class(int c, const char *s){
+ return s && (strchr(s, c) != 0);
+}
+
+/** Determine if a character is in the space class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_space_class(int c){
+ return in_class(c, space_class);
+}
+
+static inline int in_comment_class(int c){
+ return in_class(c, comment_class);
+}
+
+/** Determine if a character is in the separator class.
+ * Separator characters terminate tokens, and do not need space
+ * to separate them.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_sep_class(int c){
+ return in_class(c, sep_class);
+}
+
+/** Determine if a character is in the alpha class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_alpha_class(int c){
+ return isalpha(c);
+}
+
+/** Determine if a character is in the octal digit class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_octal_digit_class(int c){
+ return '0' <= c && c <= '7';
+}
+
+/** Determine if a character is in the decimal digit class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_decimal_digit_class(int c){
+ return isdigit(c);
+}
+
+/** Determine if a character is in the hex digit class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_hex_digit_class(int c){
+ return isdigit(c) || in_class(c, "abcdefABCDEF");
+}
+
+
+static inline int in_string_quote_class(int c){
+ return in_class(c, "'\"");
+}
+
+static inline int in_printable_class(int c){
+ return ('A' <= c && c <= 'Z')
+ || ('a' <= c && c <= 'z')
+ || ('0' <= c && c <= '9')
+ || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~");
+}
+
+extern int is_decimal_number(const char *s, int n);
+extern int is_hex_number(const char *s, int n);
+extern int is_keyword(const char *s, const char *k);
+extern int is_keychar(const char *s, char c);
+
+#endif /* !_XUTIL_LEXIS_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * An IOStream implementation using sockets.
+ */
+#ifndef __KERNEL__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "allocate.h"
+#include "socket_stream.h"
+
+#define MODULE_NAME "sock"
+#define DEBUG 0
+//#undef DEBUG
+#include "debug.h"
+
+static int socket_read(IOStream *s, void *buf, size_t n);
+static int socket_write(IOStream *s, const void *buf, size_t n);
+static int socket_error(IOStream *s);
+static int socket_close(IOStream *s);
+static void socket_free(IOStream *s);
+static int socket_flush(IOStream *s);
+
+/** Methods used by a socket IOStream. */
+static const IOMethods socket_methods = {
+ read: socket_read,
+ write: socket_write,
+ error: socket_error,
+ close: socket_close,
+ free: socket_free,
+ flush: socket_flush,
+};
+
+/** Get the socket data.
+ *
+ * @param io socket stream
+ * @return data
+ */
+static inline SocketData * socket_data(IOStream *io){
+ return (SocketData *)io->data;
+}
+
+/** Test if a stream is a socket stream.
+ *
+ * @param io stream
+ * @return 0 if a socket stream, -EINVAL if not
+ */
+int socket_stream_check(IOStream *io){
+ return (io && io->methods == &socket_methods ? 0 : -EINVAL);
+}
+
+/** Get the data for a socket stream.
+ *
+ * @param io stream
+ * @param data return value for the data
+ * @return 0 if a socket stream, -EINVAL if not
+ */
+int socket_stream_data(IOStream *io, SocketData **data){
+ int err = socket_stream_check(io);
+ if(err){
+ *data = NULL;
+ } else {
+ *data = socket_data(io);
+ }
+ return err;
+}
+
+/** Set the destination address for a socket stream.
+ *
+ * @param io stream
+ * @param addr address
+ * @return 0 if a socket stream, -EINVAL if not
+ */
+int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){
+ int err = 0;
+ SocketData *data = NULL;
+ err = socket_stream_data(io, &data);
+ if(!err){
+ data->daddr = *addr;
+ }
+ return err;
+}
+
+/** Set the send flags for a socket stream.
+ *
+ * @param io stream
+ * @param flags flags
+ * @return 0 if a socket stream, -EINVAL if not
+ */
+int socket_stream_set_flags(IOStream *io, int flags){
+ int err = 0;
+ SocketData *data = NULL;
+ err = socket_stream_data(io, &data);
+ if(!err){
+ data->flags = flags;
+ }
+ return err;
+}
+
+/** Write to the underlying socket using sendto.
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to write
+ * @return number of bytes written
+ */
+static int socket_write(IOStream *s, const void *buf, size_t n){
+ SocketData *data = socket_data(s);
+ struct sockaddr *daddr = (struct sockaddr *)&data->daddr;
+ socklen_t daddr_n = sizeof(data->daddr);
+ int k;
+ dprintf("> sock=%d addr=%s:%d n=%d\n",
+ data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n);
+ if(0){
+ struct sockaddr_in self = {};
+ socklen_t self_n;
+ getsockname(data->fd, (struct sockaddr *)&self, &self_n);
+ dprintf("> sockname sock=%d %s:%d\n",
+ data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port));
+ }
+ k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n);
+ dprintf("> sendto=%d\n", k);
+ return k;
+}
+
+/** Read from the underlying stream using recv();
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to read
+ * @return number of bytes read
+ */
+static int socket_read(IOStream *s, void *buf, size_t n){
+ SocketData *data = socket_data(s);
+ int k;
+ struct sockaddr *saddr = (struct sockaddr *)&data->saddr;
+ socklen_t saddr_n = sizeof(data->saddr);
+ k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n);
+ return k;
+}
+
+/** Flush the socket (no-op).
+ *
+ * @param s socket stream
+ * @return 0 on success, error code otherwise
+ */
+static int socket_flush(IOStream *s){
+ return 0;
+}
+
+/** Check if a socket stream has an error (no-op).
+ *
+ * @param s socket stream
+ * @return 1 if has an error, 0 otherwise
+ */
+static int socket_error(IOStream *s){
+ // Read SOL_SOCKET/SO_ERROR ?
+ return 0;
+}
+
+/** Close a socket stream.
+ *
+ * @param s socket stream to close
+ * @return result of the close
+ */
+static int socket_close(IOStream *s){
+ SocketData *data = socket_data(s);
+ return close(data->fd);
+}
+
+/** Free a socket stream.
+ *
+ * @param s socket stream
+ */
+static void socket_free(IOStream *s){
+ SocketData *data = socket_data(s);
+ deallocate(data);
+}
+
+/** Create an IOStream for a socket.
+ *
+ * @param fd socket to wtap
+ * @return new IOStream using fd for i/o
+ */
+IOStream *socket_stream_new(int fd){
+ int err = -ENOMEM;
+ IOStream *io = NULL;
+ SocketData *data = NULL;
+
+ io = ALLOCATE(IOStream);
+ if(!io) goto exit;
+ io->methods = &socket_methods;
+ data = ALLOCATE(SocketData);
+ if(!data) goto exit;
+ io->data = data;
+ data->fd = fd;
+ data->buf_n = sizeof(data->buf);
+ err = 0;
+ exit:
+ if(err){
+ if(io){
+ if(data) deallocate(data);
+ deallocate(io);
+ io = NULL;
+ }
+ }
+ return io;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_SOCKET_STREAM_H_
+#define _XEN_LIB_SOCKET_STREAM_H_
+
+#ifndef __KERNEL__
+#include "iostream.h"
+#include <stdio.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/** Data associated with a socket stream. */
+typedef struct SocketData {
+ /** The socket file descriptor. */
+ int fd;
+ /** Source address from last read (recvfrom). */
+ struct sockaddr_in saddr;
+ /** Destination address for writes (sendto). */
+ struct sockaddr_in daddr;
+ /** Write flags (sendto). */
+ int flags;
+ /** Buffer size. */
+ int buf_n;
+ /** Buffer for formatted printing. */
+ char buf[1024];
+} SocketData;
+
+extern IOStream *socket_stream_new(int fd);
+extern int socket_stream_data(IOStream *io, SocketData **data);
+extern int socket_stream_check(IOStream *io);
+extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr);
+extern int socket_stream_set_flags(IOStream *io, int flags);
+
+#endif
+#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */
/*
- * Copyright (C) 2001, 2002 Hewlett-Packard Company.
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
/*
- * Copyright (C) 2001, 2002 Hewlett-Packard Company.
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include "sys_string.h"
+#include "lexis.h"
+#include "sys_net.h"
+#include "hash_table.h"
+#include "sxpr.h"
+
+#ifdef __KERNEL__
+#include <linux/errno.h>
+#else
+#include <errno.h>
+#endif
+
+#undef free
+
+/** @file
+ * General representation of sxprs.
+ * Includes print, equal, and free functions for the sxpr types.
+ *
+ * Zero memory containing an Sxpr will have the value ONONE - this is intentional.
+ * When a function returning an sxpr cannot allocate memory we return ONOMEM.
+ *
+ */
+
+static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
+static int atom_equal(Sxpr x, Sxpr y);
+static void atom_free(Sxpr obj);
+
+static int string_print(IOStream *io, Sxpr obj, unsigned flags);
+static int string_equal(Sxpr x, Sxpr y);
+static void string_free(Sxpr obj);
+
+static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
+static int cons_equal(Sxpr x, Sxpr y);
+static void cons_free(Sxpr obj);
+
+static int null_print(IOStream *io, Sxpr obj, unsigned flags);
+static int none_print(IOStream *io, Sxpr obj, unsigned flags);
+static int int_print(IOStream *io, Sxpr obj, unsigned flags);
+static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
+
+/** Type definitions. */
+static SxprType types[1024] = {
+ [T_NONE] { type: T_NONE, name: "none", print: none_print },
+ [T_NULL] { type: T_NULL, name: "null", print: null_print },
+ [T_UINT] { type: T_UINT, name: "int", print: int_print, },
+ [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, },
+ [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print,
+ pointer: TRUE,
+ free: atom_free,
+ equal: atom_equal,
+ },
+ [T_STRING] { type: T_STRING, name: "string", print: string_print,
+ pointer: TRUE,
+ free: string_free,
+ equal: string_equal,
+ },
+ [T_CONS] { type: T_CONS, name: "cons", print: cons_print,
+ pointer: TRUE,
+ free: cons_free,
+ equal: cons_equal,
+ },
+};
+
+/** Number of entries in the types array. */
+static int type_sup = sizeof(types)/sizeof(types[0]);
+
+/** Get the type definition for a given type code.
+ *
+ * @param ty type code
+ * @return type definition or null
+ */
+SxprType *get_sxpr_type(int ty){
+ if(0 <= ty && ty < type_sup){
+ return types+ty;
+ }
+ return NULL;
+}
+
+/** The default print function.
+ *
+ * @param io stream to print to
+ * @param x sxpr to print
+ * @param flags print flags
+ * @return number of bytes written on success
+ */
+int default_print(IOStream *io, Sxpr x, unsigned flags){
+ return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));
+}
+
+/** The default equal function.
+ * Uses eq().
+ *
+ * @param x sxpr to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int default_equal(Sxpr x, Sxpr y){
+ return eq(x, y);
+}
+
+/** General sxpr print function.
+ * Prints an sxpr on a stream using the print function for the sxpr type.
+ * Printing is controlled by flags from the PrintFlags enum.
+ * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr
+ * (for debugging).
+ *
+ * @param io stream to print to
+ * @param x sxpr to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+int objprint(IOStream *io, Sxpr x, unsigned flags){
+ SxprType *def = get_sxpr_type(get_type(x));
+ ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);
+ int k = 0;
+ if(!io) return k;
+ if(flags & PRINT_TYPE){
+ k += IOStream_print(io, "%s:", def->name);
+ }
+ k += print_fn(io, x, flags);
+ return k;
+}
+
+/** General sxpr free function.
+ * Frees an sxpr using the free function for its type.
+ * Free functions must recursively free any subsxprs.
+ * If no function is defined then the default is to
+ * free sxprs whose type has pointer true.
+ * Sxprs must not be used after freeing.
+ *
+ * @param x sxpr to free
+ */
+void objfree(Sxpr x){
+ SxprType *def = get_sxpr_type(get_type(x));
+
+ if(def){
+ if(def->free){
+ def->free(x);
+ } else if (def->pointer){
+ hfree(x);
+ }
+ }
+}
+
+/** General sxpr equality function.
+ * Compares x and y using the equal function for x.
+ * Uses default_equal() if x has no equal function.
+ *
+ * @param x sxpr to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int objequal(Sxpr x, Sxpr y){
+ SxprType *def = get_sxpr_type(get_type(x));
+ ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);
+ return equal_fn(x, y);
+}
+
+/** Search for a key in an alist.
+ * An alist is a list of conses, where the cars
+ * of the conses are the keys. Compares keys using equality.
+ *
+ * @param k key
+ * @param l alist to search
+ * @return first element of l with car k, or ONULL
+ */
+Sxpr assoc(Sxpr k, Sxpr l){
+ for( ; CONSP(l) ; l = CDR(l)){
+ Sxpr x = CAR(l);
+ if(CONSP(x) && objequal(k, CAR(x))){
+ return x;
+ }
+ }
+ return ONULL;
+}
+
+/** Search for a key in an alist.
+ * An alist is a list of conses, where the cars
+ * of the conses are the keys. Compares keys using eq.
+ *
+ * @param k key
+ * @param l alist to search
+ * @return first element of l with car k, or ONULL
+ */
+Sxpr assocq(Sxpr k, Sxpr l){
+ for( ; CONSP(l); l = CDR(l)){
+ Sxpr x = CAR(l);
+ if(CONSP(x) && eq(k, CAR(x))){
+ return x;
+ }
+ }
+ return ONULL;
+}
+
+/** Add a new key and value to an alist.
+ *
+ * @param k key
+ * @param l value
+ * @param l alist
+ * @return l with the new cell added to the front
+ */
+Sxpr acons(Sxpr k, Sxpr v, Sxpr l){
+ Sxpr x, y;
+ x = cons_new(k, v);
+ if(NOMEMP(x)) return x;
+ y = cons_new(x, l);
+ if(NOMEMP(y)) cons_free_cells(x);
+ return y;
+}
+
+/** Test if a list contains an element.
+ * Uses sxpr equality.
+ *
+ * @param l list
+ * @param x element to look for
+ * @return a tail of l with x as car, or ONULL
+ */
+Sxpr cons_member(Sxpr l, Sxpr x){
+ for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}
+ return l;
+}
+
+/** Test if a list contains an element satisfying a test.
+ * The test function is called with v and an element of the list.
+ *
+ * @param l list
+ * @param test_fn test function to use
+ * @param v value for first argument to the test
+ * @return a tail of l with car satisfying the test, or 0
+ */
+Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
+ for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }
+ return l;
+}
+
+/** Test if the elements of list 't' are a subset of the elements
+ * of list 's'. Element order is not significant.
+ *
+ * @param s element list to check subset of
+ * @param t element list to check if is a subset
+ * @return 1 if is a subset, 0 otherwise
+ */
+int cons_subset(Sxpr s, Sxpr t){
+ for( ; CONSP(t); t = CDR(t)){
+ if(!CONSP(cons_member(s, CAR(t)))){
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/** Test if two lists have equal sets of elements.
+ * Element order is not significant.
+ *
+ * @param s list to check
+ * @param t list to check
+ * @return 1 if equal, 0 otherwise
+ */
+int cons_set_equal(Sxpr s, Sxpr t){
+ return cons_subset(s, t) && cons_subset(t, s);
+}
+
+#ifdef USE_GC
+/*============================================================================*/
+/* The functions inside this ifdef are only safe if GC is used.
+ * Otherwise they may leak memory.
+ */
+
+/** Remove an element from a list (GC only).
+ * Uses sxpr equality and removes all instances, even
+ * if there are more than one.
+ *
+ * @param l list to remove elements from
+ * @param x element to remove
+ * @return modified input list
+ */
+Sxpr cons_remove(Sxpr l, Sxpr x){
+ return cons_remove_if(l, eq, x);
+}
+
+/** Remove elements satisfying a test (GC only).
+ * The test function is called with v and an element of the set.
+ *
+ * @param l list to remove elements from
+ * @param test_fn function to use to decide if an element should be removed
+ * @return modified input list
+ */
+Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
+ Sxpr prev = ONULL, elt, next;
+
+ for(elt = l; CONSP(elt); elt = next){
+ next = CDR(elt);
+ if(test_fn(v, CAR(elt))){
+ if(NULLP(prev)){
+ l = next;
+ } else {
+ CDR(prev) = next;
+ }
+ }
+ }
+ return l;
+}
+
+/** Set the value for a key in an alist (GC only).
+ * If the key is present, changes the value, otherwise
+ * adds a new cell.
+ *
+ * @param k key
+ * @param v value
+ * @param l alist
+ * @return modified or extended list
+ */
+Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
+ Sxpr e = assoc(k, l);
+ if(NULLP(e)){
+ l = acons(k, v, l);
+ } else {
+ CAR(CDR(e)) = v;
+ }
+ return l;
+}
+/*============================================================================*/
+#endif /* USE_GC */
+
+/** Create a new atom with the given name.
+ *
+ * @param name the name
+ * @return new atom
+ */
+Sxpr atom_new(char *name){
+ Sxpr n, obj = ONOMEM;
+
+ n = string_new(name);
+ if(NOMEMP(n)) goto exit;
+ obj = HALLOC(ObjAtom, T_ATOM);
+ if(NOMEMP(obj)) goto exit;
+ OBJ_ATOM(obj)->name = n;
+ exit:
+ return obj;
+}
+
+/** Free an atom.
+ *
+ * @param obj to free
+ */
+void atom_free(Sxpr obj){
+ // Interned atoms are shared, so do not free.
+ if(OBJ_ATOM(obj)->interned) return;
+ objfree(OBJ_ATOM(obj)->name);
+ hfree(obj);
+}
+
+/** Print an atom. Prints the atom name.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes printed
+ */
+int atom_print(IOStream *io, Sxpr obj, unsigned flags){
+ //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
+ return string_print(io, OBJ_ATOM(obj)->name, flags);
+}
+
+/** Atom equality.
+ *
+ * @param x to compare
+ * @param y to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int atom_equal(Sxpr x, Sxpr y){
+ int ok;
+ ok = eq(x, y);
+ if(ok) goto exit;
+ ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);
+ if(ok) goto exit;
+ ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);
+ exit:
+ return ok;
+}
+
+/** Get the name of an atom.
+ *
+ * @param obj atom
+ * @return name
+ */
+char * atom_name(Sxpr obj){
+ return string_string(OBJ_ATOM(obj)->name);
+}
+
+/** Get the C string from a string sxpr.
+ *
+ * @param obj string sxpr
+ * @return string
+ */
+char * string_string(Sxpr obj){
+ return OBJ_STRING(obj);
+}
+
+/** Get the length of a string.
+ *
+ * @param obj string
+ * @return length
+ */
+int string_length(Sxpr obj){
+ return strlen(OBJ_STRING(obj));
+}
+
+/** Create a new string. The input string is copied,
+ * and must be null-terminated.
+ *
+ * @param s characters to put in the string
+ * @return new sxpr
+ */
+Sxpr string_new(char *s){
+ int n = (s ? strlen(s) : 0);
+ Sxpr obj;
+ obj = halloc(n+1, T_STRING);
+ if(!NOMEMP(obj)){
+ char *str = OBJ_STRING(obj);
+ strncpy(str, s, n);
+ str[n] = '\0';
+ }
+ return obj;
+}
+
+/** Free a string.
+ *
+ * @param obj to free
+ */
+void string_free(Sxpr obj){
+ hfree(obj);
+}
+
+/** Determine if a string needs escapes when printed
+ * using the given flags.
+ *
+ * @param str string to check
+ * @param flags print flags
+ * @return 1 if needs escapes, 0 otherwise
+ */
+int needs_escapes(char *str, unsigned flags){
+ char *c;
+ int val = 0;
+
+ if(str){
+ for(c=str; *c; c++){
+ if(in_alpha_class(*c)) continue;
+ if(in_decimal_digit_class(*c)) continue;
+ if(in_class(*c, "/._+:@~-")) continue;
+ val = 1;
+ break;
+ }
+ }
+ //printf("\n> val=%d str=|%s|\n", val, str);
+ return val;
+}
+
+/** Print a string to a stream, with escapes if necessary.
+ *
+ * @param io stream to print to
+ * @param str string
+ * @param flags print flags
+ * @return number of bytes written
+ */
+int _string_print(IOStream *io, char *str, unsigned flags){
+ int k = 0;
+ if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
+ k += IOStream_print(io, str);
+ } else {
+ k += IOStream_print(io, "\"");
+ if(str){
+ char *s;
+ for(s = str; *s; s++){
+ if(*s < ' ' || *s >= 127 ){
+ switch(*s){
+ case '\a': k += IOStream_print(io, "\\a"); break;
+ case '\b': k += IOStream_print(io, "\\b"); break;
+ case '\f': k += IOStream_print(io, "\\f"); break;
+ case '\n': k += IOStream_print(io, "\\n"); break;
+ case '\r': k += IOStream_print(io, "\\r"); break;
+ case '\t': k += IOStream_print(io, "\\t"); break;
+ case '\v': k += IOStream_print(io, "\\v"); break;
+ default:
+ // Octal escape;
+ k += IOStream_print(io, "\\%o", *s);
+ break;
+ }
+ } else if(*s == c_double_quote ||
+ *s == c_single_quote ||
+ *s == c_escape){
+ k += IOStream_print(io, "\\%c", *s);
+ } else {
+ k+= IOStream_print(io, "%c", *s);
+ }
+ }
+ }
+ k += IOStream_print(io, "\"");
+ }
+ return k;
+}
+
+/** Print a string to a stream, with escapes if necessary.
+ *
+ * @param io stream to print to
+ * @param obj string
+ * @param flags print flags
+ * @return number of bytes written
+ */
+int string_print(IOStream *io, Sxpr obj, unsigned flags){
+ return _string_print(io, OBJ_STRING(obj), flags);
+}
+
+/** Compare an sxpr with a string for equality.
+ *
+ * @param x string to compare with
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int string_equal(Sxpr x, Sxpr y){
+ int ok = 0;
+ ok = eq(x,y);
+ if(ok) goto exit;
+ ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
+ if(ok) goto exit;
+ ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
+ exit:
+ return ok;
+}
+
+/** Create a new cons cell.
+ * The cell is ONOMEM if either argument is.
+ *
+ * @param car sxpr for the car
+ * @param cdr sxpr for the cdr
+ * @return new cons
+ */
+Sxpr cons_new(Sxpr car, Sxpr cdr){
+ Sxpr obj;
+ if(NOMEMP(car) || NOMEMP(cdr)){
+ obj = ONOMEM;
+ } else {
+ obj = HALLOC(ObjCons, T_CONS);
+ if(!NOMEMP(obj)){
+ ObjCons *z = OBJ_CONS(obj);
+ z->car = car;
+ z->cdr = cdr;
+ }
+ }
+ return obj;
+}
+
+/** Push a new element onto a list.
+ *
+ * @param list list to add to
+ * @param elt element to add
+ * @return 0 if successful, error code otherwise
+ */
+int cons_push(Sxpr *list, Sxpr elt){
+ Sxpr l;
+ l = cons_new(elt, *list);
+ if(NOMEMP(l)) return -ENOMEM;
+ *list = l;
+ return 0;
+}
+
+/** Free a cons. Recursively frees the car and cdr.
+ *
+ * @param obj to free
+ */
+void cons_free(Sxpr obj){
+ Sxpr next;
+ for(; CONSP(obj); obj = next){
+ next = CDR(obj);
+ objfree(CAR(obj));
+ hfree(obj);
+ }
+ if(!NULLP(obj)){
+ objfree(obj);
+ }
+}
+
+/** Free a cons and its cdr cells, but not the car sxprs.
+ * Does nothing if called on something that is not a cons.
+ *
+ * @param obj to free
+ */
+void cons_free_cells(Sxpr obj){
+ Sxpr next;
+ for(; CONSP(obj); obj = next){
+ next = CDR(obj);
+ hfree(obj);
+ }
+}
+
+/** Print a cons.
+ * Prints the cons in list format if the cdrs are conses.
+ * uses pair (dot) format if the last cdr is not a cons (or null).
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+int cons_print(IOStream *io, Sxpr obj, unsigned flags){
+ int first = 1;
+ int k = 0;
+ k += IOStream_print(io, "(");
+ for( ; CONSP(obj) ; obj = CDR(obj)){
+ if(first){
+ first = 0;
+ } else {
+ k += IOStream_print(io, " ");
+ }
+ k += objprint(io, CAR(obj), flags);
+ }
+ if(!NULLP(obj)){
+ k += IOStream_print(io, " . ");
+ k += objprint(io, obj, flags);
+ }
+ k += IOStream_print(io, ")");
+ return (IOStream_error(io) ? -1 : k);
+}
+
+/** Compare a cons with another sxpr for equality.
+ * If y is a cons, compares the cars and cdrs recursively.
+ *
+ * @param x cons to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int cons_equal(Sxpr x, Sxpr y){
+ return CONSP(y) &&
+ objequal(CAR(x), CAR(y)) &&
+ objequal(CDR(x), CDR(y));
+}
+
+/** Return the length of a cons list.
+ *
+ * @param obj list
+ * @return length
+ */
+int cons_length(Sxpr obj){
+ int count = 0;
+ for( ; CONSP(obj); obj = CDR(obj)){
+ count++;
+ }
+ return count;
+}
+
+/** Destructively reverse a cons list in-place.
+ * If the argument is not a cons it is returned unchanged.
+ *
+ * @param l to reverse
+ * @return reversed list
+ */
+Sxpr nrev(Sxpr l){
+ if(CONSP(l)){
+ // Iterate down the cells in the list making the cdr of
+ // each cell point to the previous cell. The last cell
+ // is the head of the reversed list.
+ Sxpr prev = ONULL;
+ Sxpr cell = l;
+ Sxpr next;
+
+ while(1){
+ next = CDR(cell);
+ CDR(cell) = prev;
+ if(!CONSP(next)) break;
+ prev = cell;
+ cell = next;
+ }
+ l = cell;
+ }
+ return l;
+}
+
+/** Print the null sxpr.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int null_print(IOStream *io, Sxpr obj, unsigned flags){
+ return IOStream_print(io, "()");
+}
+
+/** Print the `unspecified' sxpr none.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int none_print(IOStream *io, Sxpr obj, unsigned flags){
+ return IOStream_print(io, "<none>");
+}
+
+/** Print an integer.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int int_print(IOStream *io, Sxpr obj, unsigned flags){
+ return IOStream_print(io, "%d", OBJ_INT(obj));
+}
+
+/** Print a boolean.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
+ return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
+}
+
+int sxprp(Sxpr obj, Sxpr name){
+ return CONSP(obj) && objequal(CAR(obj), name);
+}
+
+/** Get the name of an element.
+ *
+ * @param obj element
+ * @return name
+ */
+Sxpr sxpr_name(Sxpr obj){
+ Sxpr val = ONONE;
+ if(CONSP(obj)){
+ val = CAR(obj);
+ } else if(STRINGP(obj) || ATOMP(obj)){
+ val = obj;
+ }
+ return val;
+}
+
+int sxpr_is(Sxpr obj, char *s){
+ if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
+ if(STRINGP(obj)) return !strcmp(string_string(obj), s);
+ return 0;
+}
+
+int sxpr_elementp(Sxpr obj, Sxpr name){
+ int ok = 0;
+ ok = CONSP(obj) && objequal(CAR(obj), name);
+ return ok;
+}
+
+/** Get the attributes of an sxpr.
+ *
+ * @param obj sxpr
+ * @return attributes
+ */
+Sxpr sxpr_attributes(Sxpr obj){
+ Sxpr val = ONULL;
+ if(CONSP(obj)){
+ obj = CDR(obj);
+ if(CONSP(obj)){
+ obj = CAR(obj);
+ if(sxprp(obj, intern("@"))){
+ val = CDR(obj);
+ }
+ }
+ }
+ return val;
+}
+
+Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){
+ Sxpr val = ONONE;
+ val = assoc(sxpr_attributes(obj), key);
+ if(CONSP(val) && CONSP(CDR(val))){
+ val = CADR(def);
+ } else {
+ val = def;
+ }
+ return val;
+}
+
+/** Get the children of an sxpr.
+ *
+ * @param obj sxpr
+ * @return children
+ */
+Sxpr sxpr_children(Sxpr obj){
+ Sxpr val = ONULL;
+ if(CONSP(obj)){
+ val = CDR(obj);
+ if(CONSP(val) && sxprp(CAR(val), intern("@"))){
+ val = CDR(val);
+ }
+ }
+ return val;
+}
+
+Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){
+ Sxpr val = ONONE;
+ Sxpr l;
+ for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){
+ if(sxprp(CAR(l), name)){
+ val = CAR(l);
+ break;
+ }
+ }
+ if(NONEP(val)) val = def;
+ return val;
+}
+
+Sxpr sxpr_child0(Sxpr obj, Sxpr def){
+ Sxpr val = ONONE;
+ Sxpr l = sxpr_children(obj);
+ if(CONSP(l)){
+ val = CAR(l);
+ } else {
+ val = def;
+ }
+ return val;
+}
+
+Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def){
+ Sxpr val = def;
+ Sxpr l;
+ int i;
+ for (i = 0, l = sxpr_children(obj); CONSP(l); i++, l = CDR(l)){
+ if(i == n){
+ val = CAR(l);
+ break;
+ }
+ }
+ return val;
+}
+
+Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){
+ Sxpr val = ONONE;
+ val = sxpr_child(obj, name, ONONE);
+ if(NONEP(val)){
+ val = def;
+ } else {
+ val = sxpr_child0(val, def);
+ }
+ return val;
+}
+
+/** Table of interned symbols. Indexed by symbol name. */
+static HashTable *symbols = NULL;
+
+/** Hash function for entries in the symbol table.
+ *
+ * @param key to hash
+ * @return hashcode
+ */
+static Hashcode sym_hash_fn(void *key){
+ return hash_string((char*)key);
+}
+
+/** Key equality function for the symbol table.
+ *
+ * @param x to compare
+ * @param y to compare
+ * @return 1 if equal, 0 otherwise
+ */
+static int sym_equal_fn(void *x, void *y){
+ return !strcmp((char*)x, (char*)y);
+}
+
+/** Entry free function for the symbol table.
+ *
+ * @param table the entry is in
+ * @param entry being freed
+ */
+static void sym_free_fn(HashTable *table, HTEntry *entry){
+ if(entry){
+ objfree(((ObjAtom*)entry->value)->name);
+ HTEntry_free(entry);
+ }
+}
+
+/** Initialize the symbol table.
+ *
+ * @return 0 on sucess, error code otherwise
+ */
+static int init_symbols(void){
+ symbols = HashTable_new(100);
+ if(symbols){
+ symbols->key_hash_fn = sym_hash_fn;
+ symbols->key_equal_fn = sym_equal_fn;
+ symbols->entry_free_fn = sym_free_fn;
+ return 0;
+ }
+ return -1;
+}
+
+/** Cleanup the symbol table. Frees the table and all its symbols.
+ */
+void cleanup_symbols(void){
+ HashTable_free(symbols);
+ symbols = NULL;
+}
+
+/** Get the interned symbol with the given name.
+ * No new symbol is created.
+ *
+ * @return symbol or null
+ */
+Sxpr get_symbol(char *sym){
+ HTEntry *entry;
+ if(!symbols){
+ if(init_symbols()) return ONOMEM;
+ return ONULL;
+ }
+ entry = HashTable_get_entry(symbols, sym);
+ if(entry){
+ return OBJP(T_ATOM, entry->value);
+ } else {
+ return ONULL;
+ }
+}
+
+/** Get the interned symbol with the given name.
+ * Creates a new symbol if necessary.
+ *
+ * @return symbol
+ */
+Sxpr intern(char *sym){
+ Sxpr symbol = get_symbol(sym);
+ if(NULLP(symbol)){
+ if(!symbols) return ONOMEM;
+ symbol = atom_new(sym);
+ if(!NOMEMP(symbol)){
+ OBJ_ATOM(symbol)->interned = TRUE;
+ HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
+ }
+ }
+ return symbol;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _XUTIL_SXPR_H_
+#define _XUTIL_SXPR_H_
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
+#include "hash_table.h"
+#include "iostream.h"
+#include "allocate.h"
+
+/** @file
+ * Definitions for rules and sxprs.
+ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/** Sxpr type. */
+typedef int16_t TypeCode;
+
+/** A typed sxpr handle.*/
+typedef struct Sxpr {
+ /** Sxpr type. */
+ TypeCode type;
+ union {
+ /** Sxpr value. */
+ unsigned long ul;
+ /** Pointer. */
+ void *ptr;
+ } v;
+} Sxpr;
+
+/** Sxpr type to indicate out of memory. */
+#define T_NOMEM ((TypeCode)-1)
+/** The 'unspecified' sxpr. */
+#define T_NONE ((TypeCode)0)
+/** The empty list. */
+#define T_NULL ((TypeCode)1)
+/** Unsigned integer. */
+#define T_UINT ((TypeCode)2)
+/** A string. */
+#define T_STRING ((TypeCode)3)
+/** An atom. */
+#define T_ATOM ((TypeCode)4)
+/** A boolean. */
+#define T_BOOL ((TypeCode)5)
+
+/** A cons (pair or list). */
+#define T_CONS ((TypeCode)10)
+
+/** An error. */
+#define T_ERR ((TypeCode)40)
+
+/** An atom. */
+typedef struct ObjAtom {
+ Sxpr name;
+ Hashcode hashcode;
+ int interned;
+} ObjAtom;
+
+/** A cons (pair). */
+typedef struct ObjCons {
+ Sxpr car;
+ Sxpr cdr;
+} ObjCons;
+
+/** A vector. */
+typedef struct ObjVector {
+ int n;
+ Sxpr data[0];
+} ObjVector;
+
+/** Flags for sxpr printing. */
+enum PrintFlags {
+ PRINT_RAW = 0x001,
+ PRINT_TYPE = 0x002,
+ PRINT_PRETTY = 0x004,
+ PRINT_NUM = 0x008,
+};
+
+/** An integer sxpr.
+ *
+ * @param ty type
+ * @param val integer value
+ */
+#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
+
+/** A pointer sxpr.
+ * If the pointer is non-null, returns an sxpr containing it.
+ * If the pointer is null, returns ONOMEM.
+ *
+ * @param ty type
+ * @param val pointer
+ */
+#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
+
+/** Make an integer sxpr containing a pointer.
+ *
+ * @param val pointer
+ */
+#define PTR(val) OBJP(T_UINT, (void*)(val))
+
+/** Make an integer sxpr.
+ * @param x value
+ */
+#define OINT(x) OBJI(T_UINT, x)
+
+/** Make an error sxpr.
+ *
+ * @param x value
+ */
+#define OERR(x) OBJI(T_ERR, x)
+
+/** Out of memory constant. */
+#define ONOMEM OBJI(T_NOMEM, 0)
+
+/** The `unspecified' constant. */
+#define ONONE OBJI(T_NONE, 0)
+
+/** Empty list constant. */
+#define ONULL OBJI(T_NULL, 0)
+
+/** False constant. */
+#define OFALSE OBJI(T_BOOL, 0)
+
+/** True constant. */
+#define OTRUE OBJI(T_BOOL, 1)
+
+/* Recognizers for the various sxpr types. */
+#define ATOMP(obj) has_type(obj, T_ATOM)
+#define BOOLP(obj) has_type(obj, T_BOOL)
+#define CONSP(obj) has_type(obj, T_CONS)
+#define ERRP(obj) has_type(obj, T_ERR)
+#define INTP(obj) has_type(obj, T_UINT)
+#define NOMEMP(obj) has_type(obj, T_NOMEM)
+#define NONEP(obj) has_type(obj, T_NONE)
+#define NULLP(obj) has_type(obj, T_NULL)
+#define STRINGP(obj) has_type(obj, T_STRING)
+
+#define TRUEP(obj) get_ul(obj)
+
+/** Convert an sxpr to an unsigned integer. */
+#define OBJ_UINT(x) get_ul(x)
+/** Convert an sxpr to an integer. */
+#define OBJ_INT(x) (int)get_ul(x)
+
+/* Conversions of sxprs to their values.
+ * No checking is done.
+ */
+#define OBJ_STRING(x) ((char*)get_ptr(x))
+#define OBJ_CONS(x) ((ObjCons*)get_ptr(x))
+#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x))
+#define OBJ_SET(x) ((ObjSet*)get_ptr(x))
+#define CAR(x) (OBJ_CONS(x)->car)
+#define CDR(x) (OBJ_CONS(x)->cdr)
+
+#define CAAR(x) (CAR(CAR(x)))
+#define CADR(x) (CAR(CDR(x)))
+#define CDAR(x) (CDR(CAR(x)))
+#define CDDR(x) (CDR(CDR(x)))
+
+/** Get the integer value from an sxpr.
+ *
+ * @param obj sxpr
+ * @return value
+ */
+static inline unsigned long get_ul(Sxpr obj){
+ return obj.v.ul;
+}
+
+/** Get the pointer value from an sxpr.
+ *
+ * @param obj sxpr
+ * @return value
+ */
+static inline void * get_ptr(Sxpr obj){
+ return obj.v.ptr;
+}
+
+/** Create an sxpr containing a pointer.
+ *
+ * @param type typecode
+ * @param val pointer
+ * @return sxpr
+ */
+static inline Sxpr obj_ptr(TypeCode type, void *val){
+ return (Sxpr){ type: type, v: { ptr: val } };
+}
+
+/** Create an sxpr containing an integer.
+ *
+ * @param type typecode
+ * @param val integer
+ * @return sxpr
+ */
+static inline Sxpr obj_ul(TypeCode type, unsigned long val){
+ return (Sxpr){ type: type, v: { ul: val } };
+}
+
+/** Get the type of an sxpr.
+ *
+ * @param obj sxpr
+ * @return type
+ */
+static inline TypeCode get_type(Sxpr obj){
+ return obj.type;
+}
+
+/** Check the type of an sxpr.
+ *
+ * @param obj sxpr
+ * @param type to check
+ * @return 1 if has the type, 0 otherwise
+ */
+static inline int has_type(Sxpr obj, TypeCode type){
+ return get_type(obj) == type;
+}
+
+/** Compare sxprs for literal equality of type and value.
+ *
+ * @param x sxpr to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+static inline int eq(Sxpr x, Sxpr y){
+ return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
+}
+
+/** Checked version of CAR
+ *
+ * @param x sxpr
+ * @return CAR if a cons, x otherwise
+ */
+static inline Sxpr car(Sxpr x){
+ return (CONSP(x) ? CAR(x) : x);
+}
+
+/** Checked version of CDR.
+ *
+ * @param x sxpr
+ * @return CDR if a cons, null otherwise
+ */
+static inline Sxpr cdr(Sxpr x){
+ return (CONSP(x) ? CDR(x) : ONULL);
+}
+
+/** Allocate some memory and return an sxpr containing it.
+ * Returns ONOMEM if allocation failed.
+ *
+ * @param n number of bytes to allocate
+ * @param ty typecode
+ * @return sxpr
+ */
+static inline Sxpr halloc(size_t n, TypeCode ty){
+ return OBJP(ty, allocate(n));
+}
+
+/** Allocate an sxpr containing a pointer to the given type.
+ *
+ * @param ty type (uses sizeof to determine how many bytes to allocate)
+ * @param code typecode
+ * @return sxpr, ONOMEM if allocation failed
+ */
+#define HALLOC(ty, code) halloc(sizeof(ty), code)
+
+typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
+typedef int ObjEqualFn(Sxpr obj, Sxpr other);
+typedef void ObjFreeFn(Sxpr obj);
+
+/** An sxpr type definition. */
+typedef struct SxprType {
+ TypeCode type;
+ char *name;
+ int pointer;
+ ObjPrintFn *print;
+ ObjEqualFn *equal;
+ ObjFreeFn *free;
+} SxprType;
+
+
+extern SxprType *get_sxpr_type(int ty);
+
+/** Free the pointer in an sxpr.
+ *
+ * @param x sxpr containing a pointer
+ */
+static inline void hfree(Sxpr x){
+ deallocate(get_ptr(x));
+}
+
+extern int objprint(IOStream *io, Sxpr x, unsigned flags);
+extern int objequal(Sxpr x, Sxpr y);
+extern void objfree(Sxpr x);
+
+extern void cons_free_cells(Sxpr obj);
+extern Sxpr intern(char *s);
+
+extern Sxpr assoc(Sxpr k, Sxpr l);
+extern Sxpr assocq(Sxpr k, Sxpr l);
+extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l);
+extern Sxpr nrev(Sxpr l);
+extern Sxpr cons_member(Sxpr l, Sxpr x);
+extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
+extern int cons_subset(Sxpr s, Sxpr t);
+extern int cons_set_equal(Sxpr s, Sxpr t);
+
+#ifdef USE_GC
+extern Sxpr cons_remove(Sxpr l, Sxpr x);
+extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
+#endif
+
+extern Sxpr atom_new(char *name);
+extern char * atom_name(Sxpr obj);
+
+extern Sxpr string_new(char *s);
+extern char * string_string(Sxpr obj);
+extern int string_length(Sxpr obj);
+
+extern Sxpr cons_new(Sxpr car, Sxpr cdr);
+extern int cons_push(Sxpr *list, Sxpr elt);
+extern int cons_length(Sxpr obj);
+
+Sxpr sxpr_name(Sxpr obj);
+int sxpr_is(Sxpr obj, char *s);
+int sxpr_elementp(Sxpr obj, Sxpr name);
+Sxpr sxpr_attributes(Sxpr obj);
+Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def);
+Sxpr sxpr_children(Sxpr obj);
+Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def);
+Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def);
+Sxpr sxpr_child0(Sxpr obj, Sxpr def);
+Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def);
+
+/** Create a new atom.
+ *
+ * @param s atom name
+ * @return new atom
+ */
+static inline Sxpr mkatom(char *s){
+ return atom_new(s);
+}
+
+/** Create a new string sxpr.
+ *
+ * @param s string bytes (copied)
+ * @return new string
+ */
+static inline Sxpr mkstring(char *s){
+ return string_new(s);
+}
+
+/** Create an integer sxpr.
+ *
+ * @param i value
+ * @return sxpr
+ */
+static inline Sxpr mkint(int i){
+ return OBJI(T_UINT, i);
+}
+
+/** Create a boolean sxpr.
+ *
+ * @param b value
+ * @return sxpr
+ */
+static inline Sxpr mkbool(int b){
+ return OBJI(T_BOOL, (b ? 1 : 0));
+}
+
+/* Constants used in parsing and printing. */
+#define k_list_open "("
+#define c_list_open '('
+#define k_list_close ")"
+#define c_list_close ')'
+#define k_true "true"
+#define k_false "false"
+
+#define c_var '$'
+#define c_escape '\\'
+#define c_single_quote '\''
+#define c_double_quote '"'
+#define c_string_open c_double_quote
+#define c_string_close c_double_quote
+#define c_data_open '['
+#define c_data_close ']'
+#define c_binary '*'
+#define c_eval '!'
+#define c_concat_open '{'
+#define c_concat_close '}'
+
+#endif /* ! _XUTIL_SXPR_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef __KERNEL__
+# include <linux/config.h>
+# include <linux/module.h>
+# include <linux/kernel.h>
+# include <linux/string.h>
+# include <linux/errno.h>
+#else
+# include <stdlib.h>
+# include <errno.h>
+#endif
+
+#include "iostream.h"
+#include "lexis.h"
+#include "sxpr_parser.h"
+#include "sys_string.h"
+#include "enum.h"
+
+/** @file
+ * Sxpr parsing.
+ *
+ * So that the parser does not leak memory, all sxprs constructed by
+ * the parser must be freed on error. On successful parse the sxpr
+ * returned becomes the responsibility of the caller.
+ *
+ * @author Mike Wray <mike.wray@hpl.hp.com>
+ */
+
+#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
+#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args)
+
+static void reset(Parser *z);
+static int inputchar(Parser *p, char c);
+static int savechar(Parser *p, char c);
+extern void parse_error(Parser *in);
+extern void parse_error_id(Parser *in, ParseErrorId id);
+
+static int begin_start(Parser *p, char c);
+static int state_start(Parser *p, char c);
+static int end_start(Parser *p);
+
+static int begin_comment(Parser *p, char c);
+static int state_comment(Parser *p, char c);
+static int end_comment(Parser *p);
+
+static int begin_string(Parser *p, char c);
+static int state_string(Parser *p, char c);
+static int end_string(Parser *p);
+static int state_escape(Parser *p, char c);
+static int state_octal(Parser *p, char c);
+static int state_hex(Parser *p, char c);
+
+static int begin_atom(Parser *p, char c);
+static int state_atom(Parser *p, char c);
+static int end_atom(Parser *p);
+
+static int state_list(Parser *p, char c);
+static int begin_list(Parser *p, char c);
+static int end_list(Parser *p);
+
+/** Print a parse error.
+ *
+ * @param in parser
+ * @param msg format followed by printf arguments
+ */
+void eprintf(Parser *in, char *msg, ...){
+ va_list args;
+ if(in->error_out){
+ va_start(args, msg);
+ IOStream_vprint(in->error_out, msg, args);
+ va_end(args);
+ }
+}
+
+/** Print a parse warning.
+ *
+ * @param in parser
+ * @param msg format followed by printf arguments
+ */
+void wprintf(Parser *in, char *msg, ...){
+ va_list args;
+ if(in->error_out){
+ va_start(args, msg);
+ IOStream_vprint(in->error_out, msg, args);
+ va_end(args);
+ }
+}
+
+/*============================================================================*/
+
+/** Record defining the message for a parse error. */
+typedef struct {
+ ParseErrorId id;
+ char *message;
+} ParseError;
+
+/** Format for printing parse error messages. */
+#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s"
+
+/** Message catalog for the parse error codes. */
+static ParseError catalog[] = {
+ { PARSE_ERR_UNSPECIFIED, "unspecified error" },
+ { PARSE_ERR_NOMEM, "out of memory" },
+ { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
+ { PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
+ { PARSE_ERR_INVALID_SYNTAX, "syntax error" },
+ { PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
+ { 0, NULL }
+};
+
+/** Number of entries in the message catalog. */
+const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
+
+void ParserState_free(ParserState *z){
+ if(!z) return;
+ objfree(z->val);
+ deallocate(z);
+}
+
+int ParserState_new(ParserStateFn *fn, char *name,
+ ParserState *parent, ParserState **val){
+ int err = 0;
+ ParserState *z;
+ z = ALLOCATE(ParserState);
+ if(z){
+ z->name = name;
+ z->fn = fn;
+ z->parent = parent;
+ z->val = ONULL;
+ } else {
+ err = -ENOMEM;
+ }
+ if(!err) *val = z;
+ return err;
+}
+
+/** Free a parser.
+ * No-op if the parser is null.
+ *
+ * @param z parser
+ */
+void Parser_free(Parser *z){
+ if(!z) return;
+ objfree(z->val);
+ z->val = ONONE;
+ deallocate(z);
+}
+
+/** Create a new parser. The error stream defaults to null.
+ */
+Parser * Parser_new(void){
+ Parser *z = ALLOCATE(Parser);
+ int err = -ENOMEM;
+
+ if(!z) goto exit;
+ err = 0;
+ reset(z);
+ exit:
+ if(err){
+ Parser_free(z);
+ z = NULL;
+ }
+ return z;
+}
+
+/** Get the next character.
+ * Records the character read in the parser,
+ * and sets the line and character counts.
+ *
+ * @param p parser
+ * @return error flag: 0 on success, non-zero on error
+ */
+static int inputchar(Parser *p, char c){
+ int err = 0;
+ if(c=='\n'){
+ p->line_no++;
+ p->char_no = 0;
+ } else {
+ p->char_no++;
+ }
+ return err;
+}
+
+static int savechar(Parser *p, char c){
+ int err = 0;
+ if(p->buf_i >= p->buf_n){
+ err = -ENOMEM;
+ goto exit;
+ }
+ p->buf[p->buf_i] = c;
+ p->buf_i++;
+ exit:
+ return err;
+}
+
+int Parser_input_char(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ //skip;
+ } else {
+ inputchar(p, c);
+ }
+ if(!p->state){
+ err = begin_start(p, c);
+ if(err) goto exit;
+ }
+ err = p->state->fn(p, c);
+ exit:
+ return err;
+}
+
+int Parser_input_eof(Parser *p){
+ int err = 0;
+ p->eof = 1;
+ err = Parser_input_char(p, IOSTREAM_EOF);
+ return err;
+}
+
+int Parser_input(Parser *p, char *buf, int buf_n){
+ int err = 0;
+ int i = 0;
+ if(buf_n <= 0){
+ err = Parser_input_eof(p);
+ goto exit;
+ }
+ for(i = 0; i<buf_n; i++){
+ err = Parser_input_char(p, buf[i]);
+ if(err) goto exit;
+ }
+ exit:
+ err = (err < 0 ? err : buf_n);
+ return err;
+}
+
+int Parser_push(Parser *p, ParserStateFn *fn, char *name){
+ int err = 0;
+ err = ParserState_new(fn, name, p->state, &p->state);
+ return err;
+}
+
+int Parser_pop(Parser *p){
+ int err = 0;
+ ParserState *s = p->state;
+ p->state = s->parent;
+ ParserState_free(s);
+ return err;
+}
+
+int Parser_return(Parser *p){
+ int err = 0;
+ Sxpr val = ONONE;
+ if(!p->state){
+ err = -EINVAL;
+ goto exit;
+ }
+ val = p->state->val;
+ p->state->val = ONONE;
+ err = Parser_pop(p);
+ if(err) goto exit;
+ if(p->state){
+ err = cons_push(&p->state->val, val);
+ } else {
+ val = nrev(val);
+ p->val = val;
+ }
+ exit:
+ if(err){
+ objfree(val);
+ }
+ return err;
+}
+
+/** Determine if a character is a separator.
+ *
+ * @param p parser
+ * @param c character to test
+ * @return 1 if a separator, 0 otherwise
+ */
+static int is_separator(Parser *p, char c){
+ return in_sep_class(c);
+}
+
+/** Return the current token.
+ * The return value points at the internal buffer, so
+ * it must not be modified (or freed). Use copy_token() if you need a copy.
+ *
+ * @param p parser
+ * @return token
+ */
+char *peek_token(Parser *p){
+ return p->buf;
+}
+
+/** Return a copy of the current token.
+ * The returned value should be freed when finished with.
+ *
+ * @param p parser
+ * @return copy of token
+ */
+char *copy_token(Parser *p){
+ return strdup(peek_token(p));
+}
+
+static int do_intern(Parser *p){
+ int err = 0;
+ Sxpr obj = intern(peek_token(p));
+ if(NOMEMP(obj)){
+ err = -ENOMEM;
+ } else {
+ p->state->val = obj;
+ }
+ return err;
+}
+
+static int do_string(Parser *p){
+ int err = 0;
+ Sxpr obj;
+ obj = string_new(peek_token(p));
+ if(NOMEMP(obj)){
+ err = -ENOMEM;
+ } else {
+ p->state->val = obj;
+ }
+ return err;
+}
+
+void newtoken(Parser *p){
+ memset(p->buf, 0, p->buf_n);
+ p->buf_i = 0;
+ p->tok_begin_line = p->line_no;
+ p->tok_begin_char = p->char_no;
+}
+
+int get_escape(char c, char *d){
+ int err = 0;
+ switch(c){
+ case 'a': *d = '\a'; break;
+ case 'b': *d = '\b'; break;
+ case 'f': *d = '\f'; break;
+ case 'n': *d = '\n'; break;
+ case 'r': *d = '\r'; break;
+ case 't': *d = '\t'; break;
+ case 'v': *d = '\v'; break;
+ case c_escape: *d = c_escape; break;
+ case c_single_quote: *d = c_single_quote; break;
+ case c_double_quote: *d = c_double_quote; break;
+ default:
+ err = -EINVAL;
+ }
+ return err;
+}
+
+int Parser_ready(Parser *p){
+ return CONSP(p->val) || (p->start_state && CONSP(p->start_state->val));
+}
+
+Sxpr Parser_get_val(Parser *p){
+ Sxpr v = ONONE;
+ if(CONSP(p->val)){
+ v = CAR(p->val);
+ p->val = CDR(p->val);
+ } else if (CONSP(p->start_state->val)){
+ p->val = p->start_state->val;
+ p->val = nrev(p->val);
+ p->start_state->val = ONULL;
+ v = CAR(p->val);
+ p->val = CDR(p->val);
+ }
+ return v;
+}
+
+Sxpr Parser_get_all(Parser *p){
+ Sxpr v = ONULL;
+ if(CONSP(p->val)){
+ v = p->val;
+ p->val = ONONE;
+ } else if(CONSP(p->start_state->val)){
+ v = p->start_state->val;
+ p->start_state->val = ONULL;
+ v = nrev(v);
+ }
+ return v;
+}
+
+int begin_start(Parser *p, char c){
+ int err = 0;
+ err = Parser_push(p, state_start, "start");
+ if(err) goto exit;
+ p->start_state = p->state;
+ exit:
+ return err;
+}
+
+int state_start(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ err = end_start(p);
+ } else if(in_space_class(c)){
+ //skip
+ } else if(in_comment_class(c)){
+ begin_comment(p, c);
+ } else if(c == c_list_open){
+ begin_list(p, c);
+ } else if(c == c_list_close){
+ parse_error(p);
+ err = -EINVAL;
+ } else if(in_string_quote_class(c)){
+ begin_string(p, c);
+ } else if(in_printable_class(c)){
+ begin_atom(p, c);
+ } else if(c == 0x04){
+ //ctrl-D, EOT: end-of-text.
+ Parser_input_eof(p);
+ } else {
+ parse_error(p);
+ err = -EINVAL;
+ }
+ return err;
+}
+
+int end_start(Parser *p){
+ int err = 0;
+ err = Parser_return(p);
+ return err;
+}
+
+int begin_comment(Parser *p, char c){
+ int err = 0;
+ err = Parser_push(p, state_comment, "comment");
+ if(err) goto exit;
+ err = inputchar(p, c);
+ exit:
+ return err;
+}
+
+int state_comment(Parser *p, char c){
+ int err = 0;
+ if(c == '\n' || at_eof(p)){
+ err = end_comment(p);
+ } else {
+ err = inputchar(p, c);
+ }
+ return err;
+}
+
+int end_comment(Parser *p){
+ return Parser_pop(p);
+}
+
+int begin_string(Parser *p, char c){
+ int err = 0;
+ err = Parser_push(p, state_string, "string");
+ if(err) goto exit;
+ newtoken(p);
+ p->state->delim = c;
+ exit:
+ return err;
+}
+
+int state_string(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ } else if(c == p->state->delim){
+ err = end_string(p);
+ } else if(c == '\\'){
+ err = Parser_push(p, state_escape, "escape");
+ } else {
+ err = savechar(p, c);
+ }
+ return err;
+}
+
+int end_string(Parser *p){
+ int err = 0;
+ err = do_string(p);
+ if(err) goto exit;
+ err = Parser_return(p);
+ exit:
+ return err;
+}
+
+int state_escape(Parser *p, char c){
+ int err = 0;
+ char d;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ goto exit;
+ }
+ if(get_escape(c, &d) == 0){
+ err = savechar(p, d);
+ if(err) goto exit;
+ err = Parser_pop(p);
+ } else if(c == 'x'){
+ p->state->fn = state_hex;
+ p->state->ival = 0;
+ p->state->count = 0;
+ } else {
+ p->state->fn = state_octal;
+ p->state->ival = 0;
+ p->state->count = 0;
+ err = Parser_input_char(p, c);
+ }
+ exit:
+ return err;
+}
+
+int octaldone(Parser *p){
+ int err = 0;
+ char d = (char)(p->state->ival & 0xff);
+ err = Parser_pop(p);
+ if(err) goto exit;
+ err = Parser_input_char(p, d);
+ exit:
+ return err;
+}
+
+int octaldigit(Parser *p, char c){
+ int err = 0;
+ p->state->ival *= 8;
+ p->state->ival += c - '0';
+ p->state->count++;
+ if(err) goto exit;
+ if(p->state->ival < 0 || p->state->ival > 0xff){
+ parse_error(p);
+ err = -EINVAL;
+ goto exit;
+ }
+ if(p->state->count == 3){
+ err = octaldone(p);
+ }
+ exit:
+ return err;
+}
+
+int state_octal(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ goto exit;
+ } else if('0' <= c && c <= '7'){
+ err = octaldigit(p, c);
+ } else {
+ err = octaldone(p);
+ if(err) goto exit;
+ Parser_input_char(p, c);
+ }
+ exit:
+ return err;
+}
+
+int hexdone(Parser *p){
+ int err = 0;
+ char d = (char)(p->state->ival & 0xff);
+ err = Parser_pop(p);
+ if(err) goto exit;
+ err = Parser_input_char(p, d);
+ exit:
+ return err;
+}
+
+int hexdigit(Parser *p, char c, char d){
+ int err = 0;
+ p->state->ival *= 16;
+ p->state->ival += c - d;
+ p->state->count++;
+ if(err) goto exit;
+ if(p->state->ival < 0 || p->state->ival > 0xff){
+ parse_error(p);
+ err = -EINVAL;
+ goto exit;
+ }
+ if(p->state->count == 2){
+ err = hexdone(p);
+ }
+ exit:
+ return err;
+}
+
+int state_hex(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ goto exit;
+ } else if('0' <= c && c <= '9'){
+ err = hexdigit(p, c, '0');
+ } else if('A' <= c && c <= 'F'){
+ err = hexdigit(p, c, 'A');
+ } else if('a' <= c && c <= 'f'){
+ err = hexdigit(p, c, 'a');
+ } else if(p->state->count){
+ err =hexdone(p);
+ if(err) goto exit;
+ Parser_input_char(p, c);
+ }
+ exit:
+ return err;
+}
+
+int begin_atom(Parser *p, char c){
+ int err = 0;
+ err = Parser_push(p, state_atom, "atom");
+ if(err) goto exit;
+ newtoken(p);
+ err = savechar(p, c);
+ exit:
+ return err;
+}
+
+int state_atom(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ err = end_atom(p);
+ } else if(is_separator(p, c) ||
+ in_space_class(c) ||
+ in_comment_class(c)){
+ err = end_atom(p);
+ if(err) goto exit;
+ err = Parser_input_char(p, c);
+ } else {
+ err = savechar(p, c);
+ }
+ exit:
+ return err;
+}
+
+int end_atom(Parser *p){
+ int err = 0;
+ err = do_intern(p);
+ if(err) goto exit;
+ err = Parser_return(p);
+ exit:
+ return err;
+}
+
+int state_list(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ } else if(c == c_list_close){
+ p->state->val = nrev(p->state->val);
+ err = end_list(p);
+ } else {
+ err = state_start(p, c);
+ }
+ return err;
+
+}
+
+int begin_list(Parser *p, char c){
+ return Parser_push(p, state_list, "list");
+}
+
+int end_list(Parser *p){
+ return Parser_return(p);
+}
+
+/** Reset the fields of a parser to initial values.
+ *
+ * @param z parser
+ */
+static void reset(Parser *z){
+ IOStream *error_out = z->error_out;
+ int flags = z->flags;
+ memzero(z, sizeof(Parser));
+ z->buf_n = sizeof(z->buf) - 1;
+ z->buf_i = 0;
+ z->line_no = 1;
+ z->char_no = 0;
+ z->error_out = error_out;
+ z->flags = flags;
+}
+
+/** Set the parser error stream.
+ * Parse errors are reported on the the error stream if it is non-null.
+ *
+ * @param z parser
+ * @param error_out error stream
+ */
+void set_error_stream(Parser *z, IOStream *error_out){
+ if(z){
+ z->error_out = error_out;
+ }
+}
+
+/** Get the parser error message for an error code.
+ *
+ * @param id error code
+ * @return error message (empty string if the code is unknown)
+ */
+static char *get_message(ParseErrorId id){
+ int i;
+ for(i=0; i<catalog_n; i++){
+ if(id == catalog[i].id){
+ return catalog[i].message;
+ }
+ }
+ return "";
+}
+
+/** Get the line number.
+ *
+ * @param in parser
+ */
+int get_line(Parser *in){
+ return in->line_no;
+}
+
+/** Get the column number.
+ *
+ * @param in parser
+ */
+int get_column(Parser *in){
+ return in->char_no;
+}
+
+/** Get the line number the current token started on.
+ *
+ * @param in parser
+ */
+int get_tok_line(Parser *in){
+ return in->tok_begin_line;
+}
+
+/** Get the column number the current token started on.
+ *
+ * @param in parser
+ */
+int get_tok_column(Parser *in){
+ return in->tok_begin_char;
+}
+
+/** Report a parse error.
+ * Does nothing if the error stream is null or there is no error.
+ *
+ * @param in parser
+ */
+static void report_error(Parser *in){
+ if(in->error_out && in->err){
+ char *msg = get_message(in->err);
+ char *tok = peek_token(in);
+ IOStream_print(in->error_out, PARSE_ERR_FMT,
+ get_tok_line(in), get_tok_column(in), msg);
+ if(tok && tok[0]){
+ IOStream_print(in->error_out, " '%s'", tok);
+ }
+ IOStream_print(in->error_out, "\n");
+ }
+}
+
+/** Get the error message for the current parse error code.
+ * Does nothing if there is no error.
+ *
+ * @param in parser
+ * @param buf where to place the message
+ * @param n maximum number of characters to place in buf
+ * @return current error code (zero for no error)
+ */
+int parse_error_message(Parser *in, char *buf, int n){
+ if(in->err){
+ char *msg = get_message(in->err);
+ snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg);
+ }
+ return in->err;
+}
+
+/** Flag an unspecified parse error. All subsequent reads will fail.
+ *
+ * @param in parser
+ */
+void parse_error(Parser *in){
+ parse_error_id(in, PARSE_ERR_INVALID_SYNTAX);
+}
+
+/** Flag a parse error. All subsequent reads will fail.
+ * Does not change the parser error code if it is already set.
+ *
+ * @param in parser
+ * @param id error code
+ */
+void parse_error_id(Parser *in, ParseErrorId id){
+ if(!in->err){
+ in->err = id;
+ report_error(in);
+ }
+}
+
+/** Test if the parser's error flag is set.
+ *
+ * @param in parser
+ * @return 1 if set, 0 otherwise
+ */
+int has_error(Parser *in){
+ return (in->err > 0);
+}
+
+/** Test if the parser is at end of input.
+ *
+ * @param in parser
+ * @return 1 if at EOF, 0 otherwise
+ */
+int at_eof(Parser *p){
+ return p->eof;
+}
+
+//#define SXPR_PARSER_MAIN
+#ifdef SXPR_PARSER_MAIN
+/* Stuff for standalone testing. */
+
+#include "file_stream.h"
+#include "string_stream.h"
+
+int stringof(Sxpr exp, char **s){
+ int err = 0;
+ if(ATOMP(exp)){
+ *s = atom_name(exp);
+ } else if(STRINGP(exp)){
+ *s = string_string(exp);
+ } else {
+ err = -EINVAL;
+ *s = NULL;
+ }
+ return err;
+}
+
+int child_string(Sxpr exp, Sxpr key, char **s){
+ int err = 0;
+ Sxpr val = sxpr_child_value(exp, key, ONONE);
+ err = stringof(val, s);
+ return err;
+}
+
+int intof(Sxpr exp, int *v){
+ int err = 0;
+ char *s;
+ unsigned long l;
+ if(INTP(exp)){
+ *v = OBJ_INT(exp);
+ } else {
+ err = stringof(exp, &s);
+ if(err) goto exit;
+ err = convert_atoul(s, &l);
+ *v = (int)l;
+ }
+ exit:
+ return err;
+}
+
+int child_int(Sxpr exp, Sxpr key, int *v){
+ int err = 0;
+ Sxpr val = sxpr_child_value(exp, key, ONONE);
+ err = intof(val, v);
+ return err;
+}
+
+int eval_vnet(Sxpr exp){
+ int err = 0;
+ Sxpr oid = intern("id");
+ int id;
+ err = child_int(exp, oid, &id);
+ if(err) goto exit;
+ dprintf("> vnet id=%d\n", id);
+ exit:
+ dprintf("< err=%d\n", err);
+ return err;
+}
+
+int eval_connect(Sxpr exp){
+ int err = 0;
+ Sxpr ovif = intern("vif");
+ Sxpr ovnet = intern("vnet");
+ char *vif;
+ int vnet;
+
+ err = child_string(exp, ovif, &vif);
+ if(err) goto exit;
+ err = child_int(exp, ovnet, &vnet);
+ if(err) goto exit;
+ dprintf("> connect vif=%s vnet=%d\n", vif, vnet);
+ exit:
+ dprintf("< err=%d\n", err);
+ return err;
+}
+
+int eval(Sxpr exp){
+ int err = 0;
+ Sxpr oconnect = intern("connect");
+ Sxpr ovnet = intern("vnet");
+
+ if(sxpr_elementp(exp, ovnet)){
+ err = eval_vnet(exp);
+ } else if(sxpr_elementp(exp, oconnect)){
+ err = eval_connect(exp);
+ } else {
+ err = -EINVAL;
+ }
+ return err;
+}
+
+/** Main program for testing.
+ * Parses input and prints it.
+ *
+ * @param argc number of arguments
+ * @param argv arguments
+ * @return error code
+ */
+int main(int argc, char *argv[]){
+ Parser *pin;
+ int err = 0;
+ char buf[1024];
+ int k;
+ Sxpr obj;
+ //Sxpr l, x;
+ int i = 0;
+
+ pin = Parser_new();
+ set_error_stream(pin, iostdout);
+ dprintf("> parse...\n");
+ while(1){
+ k = fread(buf, 1, 1, stdin);
+ err = Parser_input(pin, buf, k);
+ while(Parser_ready(pin)){
+ obj = Parser_get_val(pin);
+ printf("obj %d\n", i++);
+ objprint(iostdout, obj, 0); printf("\n");
+ }
+ if(k <= 0) break;
+ }
+/* obj = Parser_get_all(pin); */
+/* for(l = obj ; CONSP(l); l = CDR(l)){ */
+/* x = CAR(l); */
+/* objprint(iostdout, x, 0); printf("\n"); */
+/* eval(x); */
+/* } */
+ dprintf("> err=%d\n", err);
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XUTIL_SXPR_PARSER_H_
+#define _XUTIL_SXPR_PARSER_H_
+
+#include "sxpr.h"
+#include "iostream.h"
+
+/** @file
+ * Sxpr parsing definitions.
+ */
+
+/** Size of a parser input buffer.
+ * Tokens read must fit into this size (including trailing null).
+ */
+#define PARSER_BUF_SIZE 1024
+
+struct Parser;
+typedef int ParserStateFn(struct Parser *, char c);
+
+typedef struct ParserState {
+ struct ParserState *parent;
+ Sxpr val;
+ int ival;
+ int count;
+ char delim;
+ ParserStateFn *fn;
+ char *name;
+} ParserState;
+
+/** Structure representing an input source for the parser.
+ * Can read from any IOStream implementation.
+ */
+typedef struct Parser {
+ Sxpr val;
+ /** Error reporting stream (null for no reports). */
+ IOStream *error_out;
+ int eof;
+ /** Error flag. Non-zero if there has been a read error. */
+ int err;
+ /** Line number on input (from 1). */
+ int line_no;
+ /** Column number of input (reset on new line). */
+ int char_no;
+ /** Lookahead character. */
+ char c;
+ /** Buffer for reading tokens. */
+ char buf[PARSER_BUF_SIZE];
+ /** Size of token buffer. */
+ int buf_n;
+ int buf_i;
+ /** Line the last token started on. */
+ int tok_begin_line;
+ /** Character number the last token started on. */
+ int tok_begin_char;
+ /** Parsing flags. */
+ int flags;
+ ParserState *state;
+ ParserState *start_state;
+} Parser;
+
+/** Parser error codes. */
+typedef enum {
+ PARSE_ERR_NONE=0,
+ PARSE_ERR_UNSPECIFIED,
+ PARSE_ERR_NOMEM,
+ PARSE_ERR_UNEXPECTED_EOF,
+ PARSE_ERR_TOKEN_TOO_LONG,
+ PARSE_ERR_INVALID_SYNTAX,
+ PARSE_ERR_INVALID_ESCAPE,
+} ParseErrorId;
+
+
+/** Parser flags. */
+//enum {
+//};
+
+/** Raise some parser flags.
+ *
+ * @param in parser
+ * @param flags flags mask
+ */
+inline static void parser_flags_raise(Parser *in, int flags){
+ in->flags |= flags;
+}
+
+/** Lower some parser flags.
+ *
+ * @param in parser
+ * @param flags flags mask
+ */
+inline static void parser_flags_lower(Parser *in, int flags){
+ in->flags &= ~flags;
+}
+
+/** Clear all parser flags.
+ *
+ * @param in parser
+ */
+inline static void parser_flags_clear(Parser *in){
+ in->flags = 0;
+}
+
+extern void Parser_free(Parser *z);
+extern Parser * Parser_new(void);
+extern int Parser_input(Parser *p, char *buf, int buf_n);
+extern int Parser_input_eof(Parser *p);
+extern int Parser_input_char(Parser *p, char c);
+extern void set_error_stream(Parser *z, IOStream *error_out);
+
+extern int parse_error_message(Parser *in, char *buf, int n);
+extern int has_error(Parser *in);
+extern int at_eof(Parser *in);
+
+int Parser_ready(Parser *p);
+Sxpr Parser_get_val(Parser *p);
+Sxpr Parser_get_all(Parser *p);
+
+#endif /* ! _XUTIL_SXPR_PARSER_H_ */
int convert_service_to_port(const char *s, unsigned long *port){
int err = 0;
unsigned long value;
- printf("%s> %s\n", __FUNCTION__, s);
if(convert_atoul(s, &value) == 0){
int ok = (0 <= value) && (value <= PORT_MAX);
- printf("> value = %ld\n", value);
if(ok){
value = htons((unsigned short)value);
} else {
err = -EINVAL;
}
} else {
- printf("> get_service_port...\n");
err = get_service_port(s, &value);
}
*port = (err ? 0: value);
- printf("%s< err=%d\n", __FUNCTION__, err);
return err;
}
--- /dev/null
+/*
+ * Copyright (C) 2002 - 2004 Mike Wray <mike.wray@hp.com>.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "sys_net.h"
+#include "sys_string.h"
+
+#ifndef __KERNEL__
+# include <grp.h>
+# include <pwd.h>
+#endif
+
+#include "util.h"
+
+
+/** @file Various utility functions.
+ */
+
+/** Print an address (in network order) as an IPv4 address string
+ * in dot notation.
+ *
+ * @param io where to print address
+ * @param address to print (in network order)
+ * @return bytes printed
+ */
+int print_address(IOStream *io, unsigned long address){
+#ifdef __KERNEL__
+ address = ntohl(address);
+ return IOStream_print(io, "%u.%u.%u.%u",
+ (unsigned)((address >> 24) & 0xff),
+ (unsigned)((address >> 16) & 0xff),
+ (unsigned)((address >> 8) & 0xff),
+ (unsigned)((address ) & 0xff));
+#else
+ struct in_addr inaddr = { s_addr: address };
+ return IOStream_print(io, inet_ntoa(inaddr));
+#endif
+}
+
+/** Get the protocol number for a protocol.
+ *
+ * @param name protocol name
+ * @param protocol where to put the protocol number
+ * @return 0 if OK, error otherwise
+ */
+int get_protocol_number(char *name, unsigned long *protocol){
+#ifdef __KERNEL__
+ return -1;
+#else
+ struct protoent *proto = getprotobyname(name);
+ if(!proto){
+ return -1;
+ }
+ *protocol = proto->p_proto;
+ return 0;
+#endif
+}
+
+/** Get the protocol name for a protocol number.
+ *
+ * @param protocol number
+ * @return name or null
+ */
+char *get_protocol_name(unsigned long protocol){
+#ifdef __KERNEL__
+ return 0;
+#else
+ struct protoent *proto = getprotobynumber(protocol);
+ if(!proto){
+ return 0;
+ }
+ return proto->p_name;
+#endif
+}
+
+/** Get the host name for an address.
+ *
+ * @param addr address
+ * @return host name or null
+ */
+char *get_host_name(unsigned long addr){
+#ifdef __KERNEL__
+ return 0;
+#else
+ struct in_addr inaddr;
+ struct hostent *host = 0;
+
+ inaddr.s_addr = addr;
+ host = gethostbyaddr((char*)&inaddr, sizeof(inaddr), AF_INET);
+ if(!host) return NULL;
+ return host->h_name;
+#endif
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 - 2004 Mike Wray <mike.wray@hp.com>.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_UTIL_H_
+#define _XEN_LIB_UTIL_H_
+
+#include "iostream.h"
+
+extern int print_address(IOStream *io, unsigned long address);
+extern int get_protocol_number(char *name, unsigned long *protocol);
+extern char *get_protocol_name(unsigned long protocol);
+extern char *get_host_name(unsigned long addr);
+
+#endif /* ! _XEN_LIB_UTIL_H_ */
XFRD_PROG_SRC =
XFRD_PROG_SRC += xfrd.c
-#XFRD_PROG_SRC += xfr_msg.c
XFRD_PROG_SRC += xen_domain.c
XFRD_PROG_SRC += select.c
XFRD_PROG_SRC += connection.c
+++ /dev/null
-/*
- * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef __KERNEL__
-#include <linux/errno.h>
-#else
-#include <errno.h>
-#endif
-
-#include "sys_string.h"
-#include "enum.h"
-
-/** Map an enum name to its value using a table.
- *
- * @param name enum name
- * @param defs enum definitions
- * @return enum value or -1 if not known
- */
-int enum_name_to_val(char *name, EnumDef *defs){
- int val = -1;
- for(; defs->name; defs++){
- if(!strcmp(defs->name, name)){
- val = defs->val;
- break;
- }
- }
- return val;
-}
-
-/** Map an enum value to its name using a table.
- *
- * @param val enum value
- * @param defs enum definitions
- * @param defs_n number of definitions
- * @return enum name or NULL if not known
- */
-char *enum_val_to_name(int val, EnumDef *defs){
- char *name = NULL;
- for(; defs->name; defs++){
- if(val == defs->val){
- name = defs->name;
- break;
- }
- }
- return name;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_ENUM_H_
-#define _XUTIL_ENUM_H_
-
-/** Mapping of an enum value to a name. */
-typedef struct EnumDef {
- int val;
- char *name;
-} EnumDef;
-
-extern int enum_name_to_val(char *name, EnumDef *defs);
-extern char *enum_val_to_name(int val, EnumDef *defs);
-
-#endif /* _XUTIL_ENUM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef __KERNEL__
-# include <linux/config.h>
-# include <linux/module.h>
-# include <linux/kernel.h>
-# include <linux/errno.h>
-#else
-# include <errno.h>
-# include <stddef.h>
-#endif
-
-//#include <limits.h>
-
-#include "allocate.h"
-#include "hash_table.h"
-
-/** @file
- * Base support for hashtables.
- *
- * Hash codes are reduced modulo the number of buckets to index tables,
- * so there is no need for hash functions to limit the range of hashcodes.
- * In fact it is assumed that hashcodes do not change when the number of
- * buckets in the table changes.
- */
-
-/*==========================================================================*/
-/** Number of bits in half a word. */
-//#if __WORDSIZE == 64
-//#define HALF_WORD_BITS 32
-//#else
-#define HALF_WORD_BITS 16
-//#endif
-
-/** Mask for lo half of a word. On 32-bit this is
- * (1<<16) - 1 = 65535 = 0xffff
- * It's 4294967295 = 0xffffffff on 64-bit.
- */
-#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1)
-
-/** Get the lo half of a word. */
-#define LO_HALF(x) ((x) & LO_HALF_MASK)
-
-/** Get the hi half of a word. */
-#define HI_HALF(x) ((x) >> HALF_WORD_BITS)
-
-/** Do a full hash on both inputs, using DES-style non-linear scrambling.
- * Both inputs are replaced with the results of the hash.
- *
- * @param pleft input/output word
- * @param pright input/output word
- */
-void pseudo_des(unsigned long *pleft, unsigned long *pright){
- // Bit-rich mixing constant.
- static const unsigned long a_mixer[] = {
- 0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, };
-
- // Bit-rich mixing constant.
- static const unsigned long b_mixer[] = {
- 0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, };
-
- // Number of iterations - must be 2 or 4.
- static const int ncycle = 4;
- //static const int ncycle = 2;
-
- unsigned long left = *pleft, right = *pright;
- unsigned long v, v_hi, v_lo;
- int i;
-
- for(i=0; i<ncycle; i++){
- // Flip some bits in right to get v.
- v = right;
- v ^= a_mixer[i];
- // Get lo and hi halves of v.
- v_lo = LO_HALF(v);
- v_hi = HI_HALF(v);
- // Non-linear mix of the halves of v.
- v = ((v_lo * v_lo) + ~(v_hi * v_hi));
- // Swap the halves of v.
- v = (HI_HALF(v) | (LO_HALF(v) << HALF_WORD_BITS));
- // Flip some bits.
- v ^= b_mixer[i];
- // More non-linear mixing.
- v += (v_lo * v_hi);
- v ^= left;
- left = right;
- right = v;
- }
- *pleft = left;
- *pright = right;
-}
-
-/** Hash a string.
- *
- * @param s input to hash
- * @return hashcode
- */
-Hashcode hash_string(char *s){
- Hashcode h = 0;
- if(s){
- for( ; *s; s++){
- h = hash_2ul(h, *s);
- }
- }
- return h;
-}
-
-/** Get the bucket for a hashcode in a hash table.
- *
- * @param table to get bucket from
- * @param hashcode to get bucket for
- * @return bucket
- */
-inline HTBucket * get_bucket(HashTable *table, Hashcode hashcode){
- return table->buckets + (hashcode % table->buckets_n);
-}
-
-/** Initialize a hash table.
- * Can be safely called more than once.
- *
- * @param table to initialize
- */
-void HashTable_init(HashTable *table){
- int i;
-
- if(!table->init_done){
- table->init_done = 1;
- table->next_id = 0;
- for(i=0; i<table->buckets_n; i++){
- HTBucket *bucket = get_bucket(table, i);
- bucket->head = 0;
- bucket->count = 0;
- }
- table->entry_count = 0;
- }
-}
-
-/** Allocate a new hashtable.
- * If the number of buckets is not positive the default is used.
- * The number of buckets should usually be prime.
- *
- * @param buckets_n number of buckets
- * @return new hashtable or null
- */
-HashTable *HashTable_new(int buckets_n){
- HashTable *z = ALLOCATE(HashTable);
- if(!z) goto exit;
- if(buckets_n <= 0){
- buckets_n = HT_BUCKETS_N;
- }
- z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
- if(!z->buckets){
- deallocate(z);
- z = 0;
- goto exit;
- }
- z->buckets_n = buckets_n;
- HashTable_init(z);
- exit:
- return z;
-}
-
-/** Free a hashtable.
- * Any entries are removed and freed.
- *
- * @param h hashtable (ignored if null)
- */
-void HashTable_free(HashTable *h){
- if(h){
- HashTable_clear(h);
- deallocate(h->buckets);
- deallocate(h);
- }
-}
-
-/** Push an entry on the list in the bucket for a given hashcode.
- *
- * @param table to add entry to
- * @param hashcode for the entry
- * @param entry to add
- */
-static inline void push_on_bucket(HashTable *table, Hashcode hashcode,
- HTEntry *entry){
- HTBucket *bucket;
- HTEntry *old_head;
-
- bucket = get_bucket(table, hashcode);
- old_head = bucket->head;
- bucket->count++;
- bucket->head = entry;
- entry->next = old_head;
-}
-
-/** Change the number of buckets in a hashtable.
- * No-op if the number of buckets is not positive.
- * Existing entries are reallocated to buckets based on their hashcodes.
- * The table is unmodified if the number of buckets cannot be changed.
- *
- * @param table hashtable
- * @param buckets_n new number of buckets
- * @return 0 on success, error code otherwise
- */
-int HashTable_set_buckets_n(HashTable *table, int buckets_n){
- int err = 0;
- HTBucket *old_buckets = table->buckets;
- int old_buckets_n = table->buckets_n;
- int i;
-
- if(buckets_n <= 0){
- err = -EINVAL;
- goto exit;
- }
- table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
- if(!table->buckets){
- err = -ENOMEM;
- table->buckets = old_buckets;
- goto exit;
- }
- table->buckets_n = buckets_n;
- for(i=0; i<old_buckets_n; i++){
- HTBucket *bucket = old_buckets + i;
- HTEntry *entry, *next;
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- push_on_bucket(table, entry->hashcode, entry);
- }
- }
- deallocate(old_buckets);
- exit:
- return err;
-}
-
-/** Adjust the number of buckets so the table is neither too full nor too empty.
- * The table is unmodified if adjusting fails.
- *
- * @param table hash table
- * @param buckets_min minimum number of buckets (use default if 0 or negative)
- * @return 0 on success, error code otherwise
- */
-int HashTable_adjust(HashTable *table, int buckets_min){
- int buckets_n = 0;
- int err = 0;
- if(buckets_min <= 0) buckets_min = HT_BUCKETS_N;
- if(table->entry_count >= table->buckets_n){
- // The table is dense - expand it.
- buckets_n = 2 * table->buckets_n;
- } else if((table->buckets_n > buckets_min) &&
- (4 * table->entry_count < table->buckets_n)){
- // The table is more than minimum size and sparse - shrink it.
- buckets_n = 2 * table->entry_count;
- if(buckets_n < buckets_min) buckets_n = buckets_min;
- }
- if(buckets_n){
- err = HashTable_set_buckets_n(table, buckets_n);
- }
- return err;
-}
-
-/** Allocate a new entry for a given value.
- *
- * @param value to put in the entry
- * @return entry, or 0 on failure
- */
-HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){
- HTEntry *z = ALLOCATE(HTEntry);
- if(z){
- z->hashcode = hashcode;
- z->key = key;
- z->value = value;
- }
- return z;
-}
-
-/** Free an entry.
- *
- * @param z entry to free
- */
-inline void HTEntry_free(HTEntry *z){
- if(z){
- deallocate(z);
- }
-}
-
-/** Free an entry in a hashtable.
- * The table's entry_free_fn is used is defined, otherwise
- * the HTEntry itself is freed.
- *
- * @param table hashtable
- * @param entry to free
- */
-inline void HashTable_free_entry(HashTable *table, HTEntry *entry){
- if(!entry)return;
- if(table && table->entry_free_fn){
- table->entry_free_fn(table, entry);
- } else {
- HTEntry_free(entry);
- }
-}
-
-/** Get the first entry satisfying a test from the bucket for the
- * given hashcode.
- *
- * @param table to look in
- * @param hashcode indicates the bucket
- * @param test_fn test to apply to elements
- * @param arg first argument to calls to test_fn
- * @return entry found, or 0
- */
-inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg){
- HTBucket *bucket;
- HTEntry *entry = 0;
- HTEntry *next;
-
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(test_fn(arg, table, entry)){
- break;
- }
- }
- return entry;
-}
-
-/** Test hashtable keys for equality.
- * Uses the table's key_equal_fn if defined, otherwise pointer equality.
- *
- * @param key1 key to compare
- * @param key2 key to compare
- * @return 1 if equal, 0 otherwise
- */
-inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
- return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2);
-}
-
-/** Compute the hashcode of a hashtable key.
- * The table's key_hash_fn is used if defined, otherwise the address of
- * the key is hashed.
- *
- * @param table hashtable
- * @param key to hash
- * @return hashcode
- */
-inline Hashcode HashTable_key_hash(HashTable *table, void *key){
- return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key));
-}
-
-/** Test if an entry has a given key.
- *
- * @param arg containing key to test for
- * @param table the entry is in
- * @param entry to test
- * @return 1 if the entry has the key, 0 otherwise
- */
-static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){
- return HashTable_key_equal(table, arg.ptr, entry->key);
-}
-
-/** Get an entry with a given key.
- *
- * @param table to search
- * @param key to look for
- * @return entry if found, null otherwise
- */
-#if 0
-inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
- TableArg arg = { ptr: key };
- return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg);
-}
-#else
-inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
- Hashcode hashcode;
- HTBucket *bucket;
- HTEntry *entry = 0;
- HTEntry *next;
-
- hashcode = HashTable_key_hash(table, key);
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(HashTable_key_equal(table, key, entry->key)){
- break;
- }
- }
- return entry;
-}
-#endif
-
-/** Get the value of an entry with a given key.
- *
- * @param table to search
- * @param key to look for
- * @return value if an entry was found, null otherwise
- */
-inline void * HashTable_get(HashTable *table, void *key){
- HTEntry *entry = HashTable_get_entry(table, key);
- return (entry ? entry->value : 0);
-}
-
-/** Print the buckets in a table.
- *
- * @param table to print
- */
-void show_buckets(HashTable *table, IOStream *io){
- int i,j ;
- IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n);
- for(i=0; i<table->buckets_n; i++){
- if(0 || table->buckets[i].count>0){
- IOStream_print(io, "bucket %3d %3d %10p ", i,
- table->buckets[i].count,
- table->buckets[i].head);
- for(j = table->buckets[i].count; j>0; j--){
- IOStream_print(io, "+");
- }
- IOStream_print(io, "\n");
- }
- }
- HashTable_print(table, io);
-}
-
-/** Print an entry in a table.
- *
- * @param entry to print
- * @param arg a pointer to an IOStream to print to
- * @return 0
- */
-static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){
- IOStream *io = (IOStream*)arg.ptr;
- IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n",
- entry->hashcode % table->buckets_n,
- entry->hashcode,
- entry->index,
- entry, entry->key, entry->value);
- return 0;
-}
-
-/** Print a hash table.
- *
- * @param table to print
- */
-void HashTable_print(HashTable *table, IOStream *io){
- IOStream_print(io, "{\n");
- HashTable_map(table, print_entry, (TableArg){ ptr: io });
- IOStream_print(io, "}\n");
-}
-/*==========================================================================*/
-
-/** Get the next entry id to use for a table.
- *
- * @param table hash table
- * @return non-zero entry id
- */
-static inline unsigned long get_next_id(HashTable *table){
- unsigned long id;
-
- if(table->next_id == 0){
- table->next_id = 1;
- }
- id = table->next_id++;
- return id;
-}
-
-/** Add an entry to the bucket for the
- * given hashcode.
- *
- * @param table to insert in
- * @param hashcode indicates the bucket
- * @param key to add an entry for
- * @param value to add an entry for
- * @return entry on success, 0 on failure
- */
-inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){
- HTEntry *entry = HTEntry_new(hashcode, key, value);
- if(entry){
- entry->index = get_next_id(table);
- push_on_bucket(table, hashcode, entry);
- table->entry_count++;
- }
- return entry;
-}
-
-/** Move the front entry for a bucket to the correct point in the bucket order as
- * defined by the order function. If this is called every time a new entry is added
- * the bucket will be maintained in sorted order.
- *
- * @param table to modify
- * @param hashcode indicates the bucket
- * @param order entry comparison function
- * @return 0 if an entry was moved, 1 if not
- */
-int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){
- HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL;
- HTBucket *bucket;
- int err = 1;
-
- bucket = get_bucket(table, hashcode);
- new_entry = bucket->head;
- if(!new_entry || !new_entry->next) goto exit;
- for(entry = new_entry->next; entry; prev = entry, entry = entry->next){
- if(order(new_entry, entry) <= 0) break;
- }
- if(prev){
- err = 0;
- bucket->head = new_entry->next;
- new_entry->next = entry;
- prev->next = new_entry;
- }
- exit:
- return err;
-}
-
-/** Add an entry to a hashtable.
- * The entry is added to the bucket for its key's hashcode.
- *
- * @param table to insert in
- * @param key to add an entry for
- * @param value to add an entry for
- * @return entry on success, 0 on failure
- */
-inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){
- return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);
-}
-
-
-/** Remove entries satisfying a test from the bucket for the
- * given hashcode.
- *
- * @param table to remove from
- * @param hashcode indicates the bucket
- * @param test_fn test to apply to elements
- * @param arg first argument to calls to test_fn
- * @return number of entries removed
- */
-inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg){
- HTBucket *bucket;
- HTEntry *entry, *prev = 0, *next;
- int removed_count = 0;
-
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(test_fn(arg, table, entry)){
- if(prev){
- prev->next = next;
- } else {
- bucket->head = next;
- }
- bucket->count--;
- table->entry_count--;
- removed_count++;
- HashTable_free_entry(table, entry);
- entry = 0;
- }
- prev = entry;
- }
- return removed_count;
-}
-
-/** Remove entries with a given key.
- *
- * @param table to remove from
- * @param key of entries to remove
- * @return number of entries removed
- */
-inline int HashTable_remove(HashTable *table, void *key){
-#if 1
- Hashcode hashcode;
- HTBucket *bucket;
- HTEntry *entry, *prev = 0, *next;
- int removed_count = 0;
-
- hashcode = HashTable_key_hash(table, key);
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(HashTable_key_equal(table, key, entry->key)){
- if(prev){
- prev->next = next;
- } else {
- bucket->head = next;
- }
- bucket->count--;
- table->entry_count--;
- removed_count++;
- HashTable_free_entry(table, entry);
- entry = 0;
- }
- prev = entry;
- }
- return removed_count;
-#else
- return HashTable_remove_entry(table, HashTable_key_hash(table, key),
- has_key, (TableArg){ ptr: key});
-#endif
-}
-
-/** Remove (and free) all the entries in a bucket.
- *
- * @param bucket to clear
- */
-static inline void bucket_clear(HashTable *table, HTBucket *bucket){
- HTEntry *entry, *next;
-
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- HashTable_free_entry(table, entry);
- }
- bucket->head = 0;
- table->entry_count -= bucket->count;
- bucket->count = 0;
-}
-
-/** Remove (and free) all the entries in a table.
- *
- * @param table to clear
- */
-void HashTable_clear(HashTable *table){
- int i, n = table->buckets_n;
-
- for(i=0; i<n; i++){
- bucket_clear(table, table->buckets + i);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_HASH_TABLE_H_
-#define _XUTIL_HASH_TABLE_H_
-
-#include "iostream.h"
-
-typedef unsigned long Hashcode;
-
-/** Type used to pass parameters to table functions. */
-typedef union TableArg {
- unsigned long ul;
- void *ptr;
-} TableArg;
-
-/** An entry in a bucket list. */
-typedef struct HTEntry {
- /** Hashcode of the entry's key. */
- Hashcode hashcode;
- /** Identifier for this entry in the table. */
- int index;
- /** The key for this entry. */
- void *key;
- /** The value in this entry. */
- void *value;
- /** The next entry in the list. */
- struct HTEntry *next;
-} HTEntry;
-
-/** A bucket in a rule table. */
-typedef struct HTBucket {
- /** Number of entries in the bucket. */
- int count;
- /** First entry in the bucket (may be null). */
- HTEntry *head;
-} HTBucket;
-
-/** Default number of buckets in a hash table.
- * You want enough buckets so the lists in the buckets will typically be short.
- * It's a good idea if this is prime, since that will help to spread hashcodes
- * around the table.
- */
-//#define HT_BUCKETS_N 1
-//#define HT_BUCKETS_N 3
-//#define HT_BUCKETS_N 7
-//#define HT_BUCKETS_N 17
-//#define HT_BUCKETS_N 97
-//#define HT_BUCKETS_N 211
-//#define HT_BUCKETS_N 401
-#define HT_BUCKETS_N 1021
-
-typedef struct HashTable HashTable;
-
-/** Type for a function used to select table entries. */
-typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry);
-
-/** Type for a function to map over table entries. */
-typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry);
-
-/** Type for a function to free table entries. */
-typedef void TableFreeFn(HashTable *table, HTEntry *entry);
-
-/** Type for a function to hash table keys. */
-typedef Hashcode TableHashFn(void *key);
-
-/** Type for a function to test table keys for equality. */
-typedef int TableEqualFn(void *key1, void *key2);
-
-/** Type for a function to order table entries. */
-typedef int TableOrderFn(HTEntry *e1, HTEntry *e2);
-
-/** General hash table.
- * A hash table with a list in each bucket.
- * Functions can be supplied for freeing entries, hashing keys, and comparing keys.
- * These all default to 0, when default behaviour treating keys as integers is used.
- */
-struct HashTable {
- /** Flag indicating whether the table has been initialised. */
- int init_done;
- /** Next value for the id field in inserted rules. */
- unsigned long next_id;
- /** Number of buckets in the bucket array. */
- int buckets_n;
- /** Array of buckets, each with its own list. */
- HTBucket *buckets;
- /** Number of entries in the table. */
- int entry_count;
- /** Function to free keys and values in entries. */
- TableFreeFn *entry_free_fn;
- /** Function to hash keys. */
- TableHashFn *key_hash_fn;
- /** Function to compare keys for equality. */
- TableEqualFn *key_equal_fn;
- /** Place for the user of the table to hang extra data. */
- void *user_data;
-};
-
-extern HashTable *HashTable_new(int bucket_n);
-extern void HashTable_free(HashTable *table);
-extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value);
-extern void HTEntry_free(HTEntry *entry);
-extern int HashTable_set_bucket_n(HashTable *table, int bucket_n);
-extern void HashTable_clear(HashTable *table);
-extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value);
-extern HTEntry * HashTable_get_entry(HashTable *table, void *key);
-extern HTEntry * HashTable_add(HashTable *table, void *key, void *value);
-extern void * HashTable_get(HashTable *table, void *key);
-extern int HashTable_remove(HashTable *table, void *key);
-extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg);
-extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg);
-//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg);
-extern void HashTable_print(HashTable *table, IOStream *out);
-extern int HashTable_set_buckets_n(HashTable *table, int buckets_n);
-extern int HashTable_adjust(HashTable *table, int buckets_min);
-extern void pseudo_des(unsigned long *pleft, unsigned long *pright);
-extern Hashcode hash_string(char *s);
-
-extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order);
-
-/** Control whether to use hashing based on DES or simple
- * hashing. DES hashing is `more random' but much more expensive.
- */
-#define HASH_PSEUDO_DES 0
-
-/** Hash a long using a quick and dirty linear congruential random number generator.
- * See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator".
- *
- * @param a value to hash
- * @return hashed input
- */
-static inline unsigned long lcrng_hash(unsigned long a){
- return (1664525L * a + 1013904223L);
-}
-
-/** Hash an unsigned long.
- *
- * @param a input to hash
- * @return hashcode
- */
-static inline Hashcode hash_ul(unsigned long a){
-#if HASH_PSEUDO_DES
- unsigned long left = a;
- unsigned long right = 0L;
- pseudo_des(&left, &right);
- return right;
-#else
- a = lcrng_hash(a);
- a = lcrng_hash(a);
- return a;
-#endif
-}
-
-/** Hash two unsigned longs together.
- *
- * @param a input to hash
- * @param b input to hash
- * @return hashcode
- */
-static inline Hashcode hash_2ul(unsigned long a, unsigned long b){
-#if HASH_PSEUDO_DES
- unsigned long left = a;
- unsigned long right = b;
- pseudo_des(&left, &right);
- return right;
-#else
- a = lcrng_hash(a);
- a ^= b;
- a = lcrng_hash(a);
- return a;
-#endif
-}
-
-/** Hash a hashcode and an unsigned long together.
- *
- * @param a input hashcode
- * @param b input to hash
- * @return hashcode
- */
-static inline Hashcode hash_hul(Hashcode a, unsigned long b){
-#if HASH_PSEUDO_DES
- unsigned long left = a;
- unsigned long right = b;
- pseudo_des(&left, &right);
- return right;
-#else
- a ^= b;
- a = lcrng_hash(a);
- return a;
-#endif
-}
-
-/** Macro to declare variables for HashTable_for_each() to use.
- *
- * @param entry variable that is set to entries in the table
- */
-#define HashTable_for_decl(entry) \
- HashTable *_var_table; \
- HTBucket *_var_bucket; \
- HTBucket *_var_end; \
- HTEntry *_var_next; \
- HTEntry *entry
-
-/** Macro to iterate over the entries in a hashtable.
- * Must be in a scope where HashTable_for_decl() has been used to declare
- * variables for it to use.
- * The variable 'entry' is iterated over entries in the table.
- * The code produced is syntactically a loop, so it must be followed by
- * a loop body, typically some statements in braces:
- * HashTable_for_each(entry, table){ ...loop body... }
- *
- * HashTable_for_each() and HashTable_for_decl() cannot be used for nested
- * loops as variables will clash.
- *
- * @note The simplest way to code a direct loop over the entries in a hashtable
- * is to use a loop over the buckets, with a nested loop over the entries
- * in a bucket. Using this approach in a macro means the macro contains
- * an opening brace, and calls to it must be followed by 2 braces!
- * To avoid this the code has been restructured so that it is a for loop.
- * So that statements could be used in the test expression of the for loop,
- * we have used the gcc statement expression extension ({ ... }).
- *
- * @param entry variable to iterate over the entries
- * @param table to iterate over (non-null)
- */
-#define HashTable_for_each(entry, table) \
- _var_table = table; \
- _var_bucket = _var_table->buckets; \
- _var_end = _var_bucket + _var_table->buckets_n; \
- for(entry=0, _var_next=0; \
- ({ if(_var_next){ \
- entry = _var_next; \
- _var_next = entry->next; \
- } else { \
- while(_var_bucket < _var_end){ \
- entry = _var_bucket->head; \
- _var_bucket++; \
- if(entry){ \
- _var_next = entry->next; \
- break; \
- } \
- } \
- }; \
- entry; }); \
- entry = _var_next )
-
-/** Map a function over the entries in a table.
- * Mapping stops when the function returns a non-zero value.
- * Uses the gcc statement expression extension ({ ... }).
- *
- * @param table to map over
- * @param fn function to apply to entries
- * @param arg first argument to call the function with
- * @return 0 if fn always returned 0, first non-zero value otherwise
- */
-#define HashTable_map(table, fn, arg) \
- ({ HashTable_for_decl(_var_entry); \
- TableArg _var_arg = arg; \
- int _var_value = 0; \
- HashTable_for_each(_var_entry, table){ \
- if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \
- } \
- _var_value; })
-
-/** Cast x to the type for a key or value in a hash table.
- * This avoids compiler warnings when using short integers
- * as keys or values (especially on 64-bit platforms).
- */
-#define HKEY(x) ((void*)(unsigned long)(x))
-
-/** Cast x from the type for a key or value in a hash table.
- * to an unsigned long. This avoids compiler warnings when using
- * short integers as keys or values (especially on 64-bit platforms).
- */
-#define HVAL(x) ((unsigned long)(x))
-
-#endif /* !_XUTIL_HASH_TABLE_H_ */
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * Lexical analysis.
- */
-
-#include "sys_string.h"
-#include "lexis.h"
-#include <errno.h>
-
-/** Check if a value lies in a (closed) range.
- *
- * @param x value to test
- * @param lo low end of the range
- * @param hi high end of the range
- * @return 1 if x is in the interval [lo, hi], 0 otherwise
- */
-inline static int in_range(int x, int lo, int hi){
- return (lo <= x) && (x <= hi);
-}
-
-/** Determine if a string is an (unsigned) decimal number.
- *
- * @param s pointer to characters to test
- * @param n length of string
- * @return 1 if s is a decimal number, 0 otherwise.
- */
-int is_decimal_number(const char *s, int n){
- int i;
- if(n <= 0)return 0;
- for(i = 0; i < n; i++){
- if(!in_decimal_digit_class(s[i])) return 0;
- }
- return 1;
-}
-
-/** Determine if a string is a hex number.
- * Hex numbers are 0, or start with 0x or 0X followed
- * by a non-zero number of hex digits (0-9,a-f,A-F).
- *
- * @param s pointer to characters to test
- * @param n length of string
- * @return 1 if s is a hex number, 0 otherwise.
- */
-int is_hex_number(const char *s, int n){
- int i;
- if(n <= 0) return 0;
- if(n == 1){
- return s[0]=='0';
- }
- if(n <= 3) return 0;
- if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0;
- for(i = 2; i < n; i++){
- if(!in_hex_digit_class(s[i])) return 0;
- }
- return 1;
-}
-
-/** Test if a string matches a keyword.
- * The comparison is case-insensitive.
- * The comparison fails if either argument is null.
- *
- * @param s string
- * @param k keyword
- * @return 1 if they match, 0 otherwise
- */
-int is_keyword(const char *s, const char *k){
- return s && k && !strcasecmp(s, k);
-}
-
-/** Test if a string matches a character.
- *
- * @param s string
- * @param c character (non-null)
- * @return 1 if s contains exactly c, 0 otherwise
- */
-int is_keychar(const char *s, char c){
- return c && (s[0] == c) && !s[1];
-}
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_LEXIS_H_
-#define _XUTIL_LEXIS_H_
-
-#include "sys_string.h"
-
-#ifdef __KERNEL__
-# include <linux/ctype.h>
-#else
-# include <ctype.h>
-#endif
-
-/** @file
- * Lexical analysis.
- */
-
-/** Class of characters treated as space. */
-#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
-
-/** Class of separator characters. */
-#define sep_class "{}()<>[]@!;"
-
-#define comment_class "#"
-
-/** Determine if a character is in a given class.
- *
- * @param c character to test
- * @param s null-terminated string of characters in the class
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_class(int c, const char *s){
- return s && (strchr(s, c) != 0);
-}
-
-/** Determine if a character is in the space class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_space_class(int c){
- return in_class(c, space_class);
-}
-
-static inline int in_comment_class(int c){
- return in_class(c, comment_class);
-}
-
-/** Determine if a character is in the separator class.
- * Separator characters terminate tokens, and do not need space
- * to separate them.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_sep_class(int c){
- return in_class(c, sep_class);
-}
-
-/** Determine if a character is in the alpha class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_alpha_class(int c){
- return isalpha(c);
-}
-
-/** Determine if a character is in the octal digit class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_octal_digit_class(int c){
- return '0' <= c && c <= '7';
-}
-
-/** Determine if a character is in the decimal digit class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_decimal_digit_class(int c){
- return isdigit(c);
-}
-
-/** Determine if a character is in the hex digit class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_hex_digit_class(int c){
- return isdigit(c) || in_class(c, "abcdefABCDEF");
-}
-
-
-static inline int in_string_quote_class(int c){
- return in_class(c, "'\"");
-}
-
-static inline int in_printable_class(int c){
- return ('A' <= c && c <= 'Z')
- || ('a' <= c && c <= 'z')
- || ('0' <= c && c <= '9')
- || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~");
-}
-
-extern int is_decimal_number(const char *s, int n);
-extern int is_hex_number(const char *s, int n);
-extern int is_keyword(const char *s, const char *k);
-extern int is_keychar(const char *s, char c);
-
-#endif /* !_XUTIL_LEXIS_H_ */
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <stdarg.h>
-#include "sys_string.h"
-#include "lexis.h"
-#include "sys_net.h"
-#include "hash_table.h"
-#include "sxpr.h"
-
-#include <errno.h>
-#undef free
-
-/** @file
- * General representation of sxprs.
- * Includes print, equal, and free functions for the sxpr types.
- *
- * Zero memory containing an Sxpr will have the value ONONE - this is intentional.
- * When a function returning an sxpr cannot allocate memory we return ONOMEM.
- *
- */
-
-static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
-static int atom_equal(Sxpr x, Sxpr y);
-static void atom_free(Sxpr obj);
-
-static int string_print(IOStream *io, Sxpr obj, unsigned flags);
-static int string_equal(Sxpr x, Sxpr y);
-static void string_free(Sxpr obj);
-
-static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
-static int cons_equal(Sxpr x, Sxpr y);
-static void cons_free(Sxpr obj);
-
-static int null_print(IOStream *io, Sxpr obj, unsigned flags);
-static int none_print(IOStream *io, Sxpr obj, unsigned flags);
-static int int_print(IOStream *io, Sxpr obj, unsigned flags);
-static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
-
-/** Type definitions. */
-static SxprType types[1024] = {
- [T_NONE] { type: T_NONE, name: "none", print: none_print },
- [T_NULL] { type: T_NULL, name: "null", print: null_print },
- [T_UINT] { type: T_UINT, name: "int", print: int_print, },
- [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, },
- [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print,
- pointer: TRUE,
- free: atom_free,
- equal: atom_equal,
- },
- [T_STRING] { type: T_STRING, name: "string", print: string_print,
- pointer: TRUE,
- free: string_free,
- equal: string_equal,
- },
- [T_CONS] { type: T_CONS, name: "cons", print: cons_print,
- pointer: TRUE,
- free: cons_free,
- equal: cons_equal,
- },
-};
-
-/** Number of entries in the types array. */
-static int type_sup = sizeof(types)/sizeof(types[0]);
-
-/** Get the type definition for a given type code.
- *
- * @param ty type code
- * @return type definition or null
- */
-SxprType *get_sxpr_type(int ty){
- if(0 <= ty && ty < type_sup){
- return types+ty;
- }
- return NULL;
-}
-
-/** The default print function.
- *
- * @param io stream to print to
- * @param x sxpr to print
- * @param flags print flags
- * @return number of bytes written on success
- */
-int default_print(IOStream *io, Sxpr x, unsigned flags){
- return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));
-}
-
-/** The default equal function.
- * Uses eq().
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int default_equal(Sxpr x, Sxpr y){
- return eq(x, y);
-}
-
-/** General sxpr print function.
- * Prints an sxpr on a stream using the print function for the sxpr type.
- * Printing is controlled by flags from the PrintFlags enum.
- * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr
- * (for debugging).
- *
- * @param io stream to print to
- * @param x sxpr to print
- * @param flags print flags
- * @return number of bytes written
- */
-int objprint(IOStream *io, Sxpr x, unsigned flags){
- SxprType *def = get_sxpr_type(get_type(x));
- ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);
- int k = 0;
- if(!io) return k;
- if(flags & PRINT_TYPE){
- k += IOStream_print(io, "%s:", def->name);
- }
- k += print_fn(io, x, flags);
- return k;
-}
-
-/** General sxpr free function.
- * Frees an sxpr using the free function for its type.
- * Free functions must recursively free any subsxprs.
- * If no function is defined then the default is to
- * free sxprs whose type has pointer true.
- * Sxprs must not be used after freeing.
- *
- * @param x sxpr to free
- */
-void objfree(Sxpr x){
- SxprType *def = get_sxpr_type(get_type(x));
-
- if(def){
- if(def->free){
- def->free(x);
- } else if (def->pointer){
- hfree(x);
- }
- }
-}
-
-/** General sxpr equality function.
- * Compares x and y using the equal function for x.
- * Uses default_equal() if x has no equal function.
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int objequal(Sxpr x, Sxpr y){
- SxprType *def = get_sxpr_type(get_type(x));
- ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);
- return equal_fn(x, y);
-}
-
-/** Search for a key in an alist.
- * An alist is a list of conses, where the cars
- * of the conses are the keys. Compares keys using equality.
- *
- * @param k key
- * @param l alist to search
- * @return first element of l with car k, or ONULL
- */
-Sxpr assoc(Sxpr k, Sxpr l){
- for( ; CONSP(l) ; l = CDR(l)){
- Sxpr x = CAR(l);
- if(CONSP(x) && objequal(k, CAR(x))){
- return x;
- }
- }
- return ONULL;
-}
-
-/** Search for a key in an alist.
- * An alist is a list of conses, where the cars
- * of the conses are the keys. Compares keys using eq.
- *
- * @param k key
- * @param l alist to search
- * @return first element of l with car k, or ONULL
- */
-Sxpr assocq(Sxpr k, Sxpr l){
- for( ; CONSP(l); l = CDR(l)){
- Sxpr x = CAR(l);
- if(CONSP(x) && eq(k, CAR(x))){
- return x;
- }
- }
- return ONULL;
-}
-
-/** Add a new key and value to an alist.
- *
- * @param k key
- * @param l value
- * @param l alist
- * @return l with the new cell added to the front
- */
-Sxpr acons(Sxpr k, Sxpr v, Sxpr l){
- Sxpr x, y;
- x = cons_new(k, v);
- if(NOMEMP(x)) return x;
- y = cons_new(x, l);
- if(NOMEMP(y)) cons_free_cells(x);
- return y;
-}
-
-/** Test if a list contains an element.
- * Uses sxpr equality.
- *
- * @param l list
- * @param x element to look for
- * @return a tail of l with x as car, or ONULL
- */
-Sxpr cons_member(Sxpr l, Sxpr x){
- for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}
- return l;
-}
-
-/** Test if a list contains an element satisfying a test.
- * The test function is called with v and an element of the list.
- *
- * @param l list
- * @param test_fn test function to use
- * @param v value for first argument to the test
- * @return a tail of l with car satisfying the test, or 0
- */
-Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
- for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }
- return l;
-}
-
-/** Test if the elements of list 't' are a subset of the elements
- * of list 's'. Element order is not significant.
- *
- * @param s element list to check subset of
- * @param t element list to check if is a subset
- * @return 1 if is a subset, 0 otherwise
- */
-int cons_subset(Sxpr s, Sxpr t){
- for( ; CONSP(t); t = CDR(t)){
- if(!CONSP(cons_member(s, CAR(t)))){
- return 0;
- }
- }
- return 1;
-}
-
-/** Test if two lists have equal sets of elements.
- * Element order is not significant.
- *
- * @param s list to check
- * @param t list to check
- * @return 1 if equal, 0 otherwise
- */
-int cons_set_equal(Sxpr s, Sxpr t){
- return cons_subset(s, t) && cons_subset(t, s);
-}
-
-#ifdef USE_GC
-/*============================================================================*/
-/* The functions inside this ifdef are only safe if GC is used.
- * Otherwise they may leak memory.
- */
-
-/** Remove an element from a list (GC only).
- * Uses sxpr equality and removes all instances, even
- * if there are more than one.
- *
- * @param l list to remove elements from
- * @param x element to remove
- * @return modified input list
- */
-Sxpr cons_remove(Sxpr l, Sxpr x){
- return cons_remove_if(l, eq, x);
-}
-
-/** Remove elements satisfying a test (GC only).
- * The test function is called with v and an element of the set.
- *
- * @param l list to remove elements from
- * @param test_fn function to use to decide if an element should be removed
- * @return modified input list
- */
-Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
- Sxpr prev = ONULL, elt, next;
-
- for(elt = l; CONSP(elt); elt = next){
- next = CDR(elt);
- if(test_fn(v, CAR(elt))){
- if(NULLP(prev)){
- l = next;
- } else {
- CDR(prev) = next;
- }
- }
- }
- return l;
-}
-
-/** Set the value for a key in an alist (GC only).
- * If the key is present, changes the value, otherwise
- * adds a new cell.
- *
- * @param k key
- * @param v value
- * @param l alist
- * @return modified or extended list
- */
-Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
- Sxpr e = assoc(k, l);
- if(NULLP(e)){
- l = acons(k, v, l);
- } else {
- CAR(CDR(e)) = v;
- }
- return l;
-}
-/*============================================================================*/
-#endif /* USE_GC */
-
-/** Create a new atom with the given name.
- *
- * @param name the name
- * @return new atom
- */
-Sxpr atom_new(char *name){
- Sxpr n, obj = ONOMEM;
-
- n = string_new(name);
- if(NOMEMP(n)) goto exit;
- obj = HALLOC(ObjAtom, T_ATOM);
- if(NOMEMP(obj)) goto exit;
- OBJ_ATOM(obj)->name = n;
- exit:
- return obj;
-}
-
-/** Free an atom.
- *
- * @param obj to free
- */
-void atom_free(Sxpr obj){
- // Interned atoms are shared, so do not free.
- if(OBJ_ATOM(obj)->interned) return;
- objfree(OBJ_ATOM(obj)->name);
- hfree(obj);
-}
-
-/** Print an atom. Prints the atom name.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes printed
- */
-int atom_print(IOStream *io, Sxpr obj, unsigned flags){
- //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
- return string_print(io, OBJ_ATOM(obj)->name, flags);
-}
-
-/** Atom equality.
- *
- * @param x to compare
- * @param y to compare
- * @return 1 if equal, 0 otherwise
- */
-int atom_equal(Sxpr x, Sxpr y){
- int ok;
- ok = eq(x, y);
- if(ok) goto exit;
- ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);
- if(ok) goto exit;
- ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);
- exit:
- return ok;
-}
-
-/** Get the name of an atom.
- *
- * @param obj atom
- * @return name
- */
-char * atom_name(Sxpr obj){
- return string_string(OBJ_ATOM(obj)->name);
-}
-
-/** Get the C string from a string sxpr.
- *
- * @param obj string sxpr
- * @return string
- */
-char * string_string(Sxpr obj){
- return OBJ_STRING(obj);
-}
-
-/** Get the length of a string.
- *
- * @param obj string
- * @return length
- */
-int string_length(Sxpr obj){
- return strlen(OBJ_STRING(obj));
-}
-
-/** Create a new string. The input string is copied,
- * and must be null-terminated.
- *
- * @param s characters to put in the string
- * @return new sxpr
- */
-Sxpr string_new(char *s){
- int n = (s ? strlen(s) : 0);
- Sxpr obj;
- obj = halloc(n+1, T_STRING);
- if(!NOMEMP(obj)){
- char *str = OBJ_STRING(obj);
- strncpy(str, s, n);
- str[n] = '\0';
- }
- return obj;
-}
-
-/** Free a string.
- *
- * @param obj to free
- */
-void string_free(Sxpr obj){
- hfree(obj);
-}
-
-/** Determine if a string needs escapes when printed
- * using the given flags.
- *
- * @param str string to check
- * @param flags print flags
- * @return 1 if needs escapes, 0 otherwise
- */
-int needs_escapes(char *str, unsigned flags){
- char *c;
- int val = 0;
-
- if(str){
- for(c=str; *c; c++){
- if(in_alpha_class(*c)) continue;
- if(in_decimal_digit_class(*c)) continue;
- if(in_class(*c, "/._+:@~-")) continue;
- val = 1;
- break;
- }
- }
- //printf("\n> val=%d str=|%s|\n", val, str);
- return val;
-}
-
-/** Print a string to a stream, with escapes if necessary.
- *
- * @param io stream to print to
- * @param str string
- * @param flags print flags
- * @return number of bytes written
- */
-int _string_print(IOStream *io, char *str, unsigned flags){
- int k = 0;
- if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
- k += IOStream_print(io, str);
- } else {
- k += IOStream_print(io, "\"");
- if(str){
- char *s;
- for(s = str; *s; s++){
- if(*s < ' ' || *s >= 127 ){
- switch(*s){
- case '\a': k += IOStream_print(io, "\\a"); break;
- case '\b': k += IOStream_print(io, "\\b"); break;
- case '\f': k += IOStream_print(io, "\\f"); break;
- case '\n': k += IOStream_print(io, "\\n"); break;
- case '\r': k += IOStream_print(io, "\\r"); break;
- case '\t': k += IOStream_print(io, "\\t"); break;
- case '\v': k += IOStream_print(io, "\\v"); break;
- default:
- // Octal escape;
- k += IOStream_print(io, "\\%o", *s);
- break;
- }
- } else if(*s == c_double_quote ||
- *s == c_single_quote ||
- *s == c_escape){
- k += IOStream_print(io, "\\%c", *s);
- } else {
- k+= IOStream_print(io, "%c", *s);
- }
- }
- }
- k += IOStream_print(io, "\"");
- }
- return k;
-}
-
-/** Print a string to a stream, with escapes if necessary.
- *
- * @param io stream to print to
- * @param obj string
- * @param flags print flags
- * @return number of bytes written
- */
-int string_print(IOStream *io, Sxpr obj, unsigned flags){
- return _string_print(io, OBJ_STRING(obj), flags);
-}
-
-/** Compare an sxpr with a string for equality.
- *
- * @param x string to compare with
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int string_equal(Sxpr x, Sxpr y){
- int ok = 0;
- ok = eq(x,y);
- if(ok) goto exit;
- ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
- if(ok) goto exit;
- ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
- exit:
- return ok;
-}
-
-/** Create a new cons cell.
- * The cell is ONOMEM if either argument is.
- *
- * @param car sxpr for the car
- * @param cdr sxpr for the cdr
- * @return new cons
- */
-Sxpr cons_new(Sxpr car, Sxpr cdr){
- Sxpr obj;
- if(NOMEMP(car) || NOMEMP(cdr)){
- obj = ONOMEM;
- } else {
- obj = HALLOC(ObjCons, T_CONS);
- if(!NOMEMP(obj)){
- ObjCons *z = OBJ_CONS(obj);
- z->car = car;
- z->cdr = cdr;
- }
- }
- return obj;
-}
-
-/** Push a new element onto a list.
- *
- * @param list list to add to
- * @param elt element to add
- * @return 0 if successful, error code otherwise
- */
-int cons_push(Sxpr *list, Sxpr elt){
- Sxpr l;
- l = cons_new(elt, *list);
- if(NOMEMP(l)) return -ENOMEM;
- *list = l;
- return 0;
-}
-
-/** Free a cons. Recursively frees the car and cdr.
- *
- * @param obj to free
- */
-void cons_free(Sxpr obj){
- Sxpr next;
- for(; CONSP(obj); obj = next){
- next = CDR(obj);
- objfree(CAR(obj));
- hfree(obj);
- }
- if(!NULLP(obj)){
- objfree(obj);
- }
-}
-
-/** Free a cons and its cdr cells, but not the car sxprs.
- * Does nothing if called on something that is not a cons.
- *
- * @param obj to free
- */
-void cons_free_cells(Sxpr obj){
- Sxpr next;
- for(; CONSP(obj); obj = next){
- next = CDR(obj);
- hfree(obj);
- }
-}
-
-/** Print a cons.
- * Prints the cons in list format if the cdrs are conses.
- * uses pair (dot) format if the last cdr is not a cons (or null).
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-int cons_print(IOStream *io, Sxpr obj, unsigned flags){
- int first = 1;
- int k = 0;
- k += IOStream_print(io, "(");
- for( ; CONSP(obj) ; obj = CDR(obj)){
- if(first){
- first = 0;
- } else {
- k += IOStream_print(io, " ");
- }
- k += objprint(io, CAR(obj), flags);
- }
- if(!NULLP(obj)){
- k += IOStream_print(io, " . ");
- k += objprint(io, obj, flags);
- }
- k += IOStream_print(io, ")");
- return (IOStream_error(io) ? -1 : k);
-}
-
-/** Compare a cons with another sxpr for equality.
- * If y is a cons, compares the cars and cdrs recursively.
- *
- * @param x cons to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int cons_equal(Sxpr x, Sxpr y){
- return CONSP(y) &&
- objequal(CAR(x), CAR(y)) &&
- objequal(CDR(x), CDR(y));
-}
-
-/** Return the length of a cons list.
- *
- * @param obj list
- * @return length
- */
-int cons_length(Sxpr obj){
- int count = 0;
- for( ; CONSP(obj); obj = CDR(obj)){
- count++;
- }
- return count;
-}
-
-/** Destructively reverse a cons list in-place.
- * If the argument is not a cons it is returned unchanged.
- *
- * @param l to reverse
- * @return reversed list
- */
-Sxpr nrev(Sxpr l){
- if(CONSP(l)){
- // Iterate down the cells in the list making the cdr of
- // each cell point to the previous cell. The last cell
- // is the head of the reversed list.
- Sxpr prev = ONULL;
- Sxpr cell = l;
- Sxpr next;
-
- while(1){
- next = CDR(cell);
- CDR(cell) = prev;
- if(!CONSP(next)) break;
- prev = cell;
- cell = next;
- }
- l = cell;
- }
- return l;
-}
-
-/** Print the null sxpr.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int null_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "()");
-}
-
-/** Print the `unspecified' sxpr none.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int none_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "<none>");
-}
-
-/** Print an integer.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int int_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "%d", OBJ_INT(obj));
-}
-
-/** Print a boolean.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
-}
-
-int sxprp(Sxpr obj, Sxpr name){
- return CONSP(obj) && objequal(CAR(obj), name);
-}
-
-/** Get the name of an element.
- *
- * @param obj element
- * @return name
- */
-Sxpr sxpr_name(Sxpr obj){
- Sxpr val = ONONE;
- if(CONSP(obj)){
- val = CAR(obj);
- } else if(STRINGP(obj) || ATOMP(obj)){
- val = obj;
- }
- return val;
-}
-
-int sxpr_is(Sxpr obj, char *s){
- if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
- if(STRINGP(obj)) return !strcmp(string_string(obj), s);
- return 0;
-}
-
-int sxpr_elementp(Sxpr obj, Sxpr name){
- int ok = 0;
- ok = CONSP(obj) && objequal(CAR(obj), name);
- return ok;
-}
-
-/** Get the attributes of an sxpr.
- *
- * @param obj sxpr
- * @return attributes
- */
-Sxpr sxpr_attributes(Sxpr obj){
- Sxpr val = ONULL;
- if(CONSP(obj)){
- obj = CDR(obj);
- if(CONSP(obj)){
- obj = CAR(obj);
- if(sxprp(obj, intern("@"))){
- val = CDR(obj);
- }
- }
- }
- return val;
-}
-
-Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){
- Sxpr val = ONONE;
- val = assoc(sxpr_attributes(obj), key);
- if(CONSP(val) && CONSP(CDR(val))){
- val = CADR(def);
- } else {
- val = def;
- }
- return val;
-}
-
-/** Get the children of an sxpr.
- *
- * @param obj sxpr
- * @return children
- */
-Sxpr sxpr_children(Sxpr obj){
- Sxpr val = ONULL;
- if(CONSP(obj)){
- val = CDR(obj);
- if(CONSP(val) && sxprp(CAR(val), intern("@"))){
- val = CDR(val);
- }
- }
- return val;
-}
-
-Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){
- Sxpr val = ONONE;
- Sxpr l;
- for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){
- if(sxprp(CAR(l), name)){
- val = CAR(l);
- break;
- }
- }
- if(NONEP(val)) val = def;
- return val;
-}
-
-Sxpr sxpr_child0(Sxpr obj, Sxpr def){
- Sxpr val = ONONE;
- Sxpr l = sxpr_children(obj);
- if(CONSP(l)){
- val = CAR(l);
- } else {
- val = def;
- }
- return val;
-}
-
-Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def){
- Sxpr val = def;
- Sxpr l;
- int i;
- for (i = 0, l = sxpr_children(obj); CONSP(l); i++, l = CDR(l)){
- if(i == n){
- val = CAR(l);
- break;
- }
- }
- return val;
-}
-
-Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){
- Sxpr val = ONONE;
- val = sxpr_child(obj, name, ONONE);
- if(NONEP(val)){
- val = def;
- } else {
- val = sxpr_child0(val, def);
- }
- return val;
-}
-
-/** Table of interned symbols. Indexed by symbol name. */
-static HashTable *symbols = NULL;
-
-/** Hash function for entries in the symbol table.
- *
- * @param key to hash
- * @return hashcode
- */
-static Hashcode sym_hash_fn(void *key){
- return hash_string((char*)key);
-}
-
-/** Key equality function for the symbol table.
- *
- * @param x to compare
- * @param y to compare
- * @return 1 if equal, 0 otherwise
- */
-static int sym_equal_fn(void *x, void *y){
- return !strcmp((char*)x, (char*)y);
-}
-
-/** Entry free function for the symbol table.
- *
- * @param table the entry is in
- * @param entry being freed
- */
-static void sym_free_fn(HashTable *table, HTEntry *entry){
- if(entry){
- objfree(((ObjAtom*)entry->value)->name);
- HTEntry_free(entry);
- }
-}
-
-/** Initialize the symbol table.
- *
- * @return 0 on sucess, error code otherwise
- */
-static int init_symbols(void){
- symbols = HashTable_new(100);
- if(symbols){
- symbols->key_hash_fn = sym_hash_fn;
- symbols->key_equal_fn = sym_equal_fn;
- symbols->entry_free_fn = sym_free_fn;
- return 0;
- }
- return -1;
-}
-
-/** Cleanup the symbol table. Frees the table and all its symbols.
- */
-void cleanup_symbols(void){
- HashTable_free(symbols);
- symbols = NULL;
-}
-
-/** Get the interned symbol with the given name.
- * No new symbol is created.
- *
- * @return symbol or null
- */
-Sxpr get_symbol(char *sym){
- HTEntry *entry;
- if(!symbols){
- if(init_symbols()) return ONOMEM;
- return ONULL;
- }
- entry = HashTable_get_entry(symbols, sym);
- if(entry){
- return OBJP(T_ATOM, entry->value);
- } else {
- return ONULL;
- }
-}
-
-/** Get the interned symbol with the given name.
- * Creates a new symbol if necessary.
- *
- * @return symbol
- */
-Sxpr intern(char *sym){
- Sxpr symbol = get_symbol(sym);
- if(NULLP(symbol)){
- if(!symbols) return ONOMEM;
- symbol = atom_new(sym);
- if(!NOMEMP(symbol)){
- OBJ_ATOM(symbol)->interned = TRUE;
- HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
- }
- }
- return symbol;
-}
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _XUTIL_SXPR_H_
-#define _XUTIL_SXPR_H_
-
-#include <stdint.h>
-
-#include "hash_table.h"
-#include "iostream.h"
-#include "allocate.h"
-
-/** @file
- * Definitions for rules and sxprs.
- */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-/** Sxpr type. */
-typedef int16_t TypeCode;
-
-/** A typed sxpr handle.*/
-typedef struct Sxpr {
- /** Sxpr type. */
- TypeCode type;
- union {
- /** Sxpr value. */
- unsigned long ul;
- /** Pointer. */
- void *ptr;
- } v;
-} Sxpr;
-
-/** Sxpr type to indicate out of memory. */
-#define T_NOMEM ((TypeCode)-1)
-/** The 'unspecified' sxpr. */
-#define T_NONE ((TypeCode)0)
-/** The empty list. */
-#define T_NULL ((TypeCode)1)
-/** Unsigned integer. */
-#define T_UINT ((TypeCode)2)
-/** A string. */
-#define T_STRING ((TypeCode)3)
-/** An atom. */
-#define T_ATOM ((TypeCode)4)
-/** A boolean. */
-#define T_BOOL ((TypeCode)5)
-
-/** A cons (pair or list). */
-#define T_CONS ((TypeCode)10)
-
-/** An error. */
-#define T_ERR ((TypeCode)40)
-
-/** An atom. */
-typedef struct ObjAtom {
- Sxpr name;
- Hashcode hashcode;
- int interned;
-} ObjAtom;
-
-/** A cons (pair). */
-typedef struct ObjCons {
- Sxpr car;
- Sxpr cdr;
-} ObjCons;
-
-/** A vector. */
-typedef struct ObjVector {
- int n;
- Sxpr data[0];
-} ObjVector;
-
-/** Flags for sxpr printing. */
-enum PrintFlags {
- PRINT_RAW = 0x001,
- PRINT_TYPE = 0x002,
- PRINT_PRETTY = 0x004,
- PRINT_NUM = 0x008,
-};
-
-/** An integer sxpr.
- *
- * @param ty type
- * @param val integer value
- */
-#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
-
-/** A pointer sxpr.
- * If the pointer is non-null, returns an sxpr containing it.
- * If the pointer is null, returns ONOMEM.
- *
- * @param ty type
- * @param val pointer
- */
-#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
-
-/** Make an integer sxpr containing a pointer.
- *
- * @param val pointer
- */
-#define PTR(val) OBJP(T_UINT, (void*)(val))
-
-/** Make an integer sxpr.
- * @param x value
- */
-#define OINT(x) OBJI(T_UINT, x)
-
-/** Make an error sxpr.
- *
- * @param x value
- */
-#define OERR(x) OBJI(T_ERR, x)
-
-/** Out of memory constant. */
-#define ONOMEM OBJI(T_NOMEM, 0)
-
-/** The `unspecified' constant. */
-#define ONONE OBJI(T_NONE, 0)
-
-/** Empty list constant. */
-#define ONULL OBJI(T_NULL, 0)
-
-/** False constant. */
-#define OFALSE OBJI(T_BOOL, 0)
-
-/** True constant. */
-#define OTRUE OBJI(T_BOOL, 1)
-
-/* Recognizers for the various sxpr types. */
-#define ATOMP(obj) has_type(obj, T_ATOM)
-#define BOOLP(obj) has_type(obj, T_BOOL)
-#define CONSP(obj) has_type(obj, T_CONS)
-#define ERRP(obj) has_type(obj, T_ERR)
-#define INTP(obj) has_type(obj, T_UINT)
-#define NOMEMP(obj) has_type(obj, T_NOMEM)
-#define NONEP(obj) has_type(obj, T_NONE)
-#define NULLP(obj) has_type(obj, T_NULL)
-#define STRINGP(obj) has_type(obj, T_STRING)
-
-#define TRUEP(obj) get_ul(obj)
-
-/** Convert an sxpr to an unsigned integer. */
-#define OBJ_UINT(x) get_ul(x)
-/** Convert an sxpr to an integer. */
-#define OBJ_INT(x) (int)get_ul(x)
-
-/* Conversions of sxprs to their values.
- * No checking is done.
- */
-#define OBJ_STRING(x) ((char*)get_ptr(x))
-#define OBJ_CONS(x) ((ObjCons*)get_ptr(x))
-#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x))
-#define OBJ_SET(x) ((ObjSet*)get_ptr(x))
-#define CAR(x) (OBJ_CONS(x)->car)
-#define CDR(x) (OBJ_CONS(x)->cdr)
-
-#define CAAR(x) (CAR(CAR(x)))
-#define CADR(x) (CAR(CDR(x)))
-#define CDAR(x) (CDR(CAR(x)))
-#define CDDR(x) (CDR(CDR(x)))
-
-/** Get the integer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline unsigned long get_ul(Sxpr obj){
- return obj.v.ul;
-}
-
-/** Get the pointer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline void * get_ptr(Sxpr obj){
- return obj.v.ptr;
-}
-
-/** Create an sxpr containing a pointer.
- *
- * @param type typecode
- * @param val pointer
- * @return sxpr
- */
-static inline Sxpr obj_ptr(TypeCode type, void *val){
- return (Sxpr){ type: type, v: { ptr: val } };
-}
-
-/** Create an sxpr containing an integer.
- *
- * @param type typecode
- * @param val integer
- * @return sxpr
- */
-static inline Sxpr obj_ul(TypeCode type, unsigned long val){
- return (Sxpr){ type: type, v: { ul: val } };
-}
-
-/** Get the type of an sxpr.
- *
- * @param obj sxpr
- * @return type
- */
-static inline TypeCode get_type(Sxpr obj){
- return obj.type;
-}
-
-/** Check the type of an sxpr.
- *
- * @param obj sxpr
- * @param type to check
- * @return 1 if has the type, 0 otherwise
- */
-static inline int has_type(Sxpr obj, TypeCode type){
- return get_type(obj) == type;
-}
-
-/** Compare sxprs for literal equality of type and value.
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-static inline int eq(Sxpr x, Sxpr y){
- return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
-}
-
-/** Checked version of CAR
- *
- * @param x sxpr
- * @return CAR if a cons, x otherwise
- */
-static inline Sxpr car(Sxpr x){
- return (CONSP(x) ? CAR(x) : x);
-}
-
-/** Checked version of CDR.
- *
- * @param x sxpr
- * @return CDR if a cons, null otherwise
- */
-static inline Sxpr cdr(Sxpr x){
- return (CONSP(x) ? CDR(x) : ONULL);
-}
-
-/** Allocate some memory and return an sxpr containing it.
- * Returns ONOMEM if allocation failed.
- *
- * @param n number of bytes to allocate
- * @param ty typecode
- * @return sxpr
- */
-static inline Sxpr halloc(size_t n, TypeCode ty){
- return OBJP(ty, allocate(n));
-}
-
-/** Allocate an sxpr containing a pointer to the given type.
- *
- * @param ty type (uses sizeof to determine how many bytes to allocate)
- * @param code typecode
- * @return sxpr, ONOMEM if allocation failed
- */
-#define HALLOC(ty, code) halloc(sizeof(ty), code)
-
-typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
-typedef int ObjEqualFn(Sxpr obj, Sxpr other);
-typedef void ObjFreeFn(Sxpr obj);
-
-/** An sxpr type definition. */
-typedef struct SxprType {
- TypeCode type;
- char *name;
- int pointer;
- ObjPrintFn *print;
- ObjEqualFn *equal;
- ObjFreeFn *free;
-} SxprType;
-
-
-extern SxprType *get_sxpr_type(int ty);
-
-/** Free the pointer in an sxpr.
- *
- * @param x sxpr containing a pointer
- */
-static inline void hfree(Sxpr x){
- deallocate(get_ptr(x));
-}
-
-extern int objprint(IOStream *io, Sxpr x, unsigned flags);
-extern int objequal(Sxpr x, Sxpr y);
-extern void objfree(Sxpr x);
-
-extern void cons_free_cells(Sxpr obj);
-extern Sxpr intern(char *s);
-
-extern Sxpr assoc(Sxpr k, Sxpr l);
-extern Sxpr assocq(Sxpr k, Sxpr l);
-extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l);
-extern Sxpr nrev(Sxpr l);
-extern Sxpr cons_member(Sxpr l, Sxpr x);
-extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
-extern int cons_subset(Sxpr s, Sxpr t);
-extern int cons_set_equal(Sxpr s, Sxpr t);
-
-#ifdef USE_GC
-extern Sxpr cons_remove(Sxpr l, Sxpr x);
-extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
-#endif
-
-extern Sxpr atom_new(char *name);
-extern char * atom_name(Sxpr obj);
-
-extern Sxpr string_new(char *s);
-extern char * string_string(Sxpr obj);
-extern int string_length(Sxpr obj);
-
-extern Sxpr cons_new(Sxpr car, Sxpr cdr);
-extern int cons_push(Sxpr *list, Sxpr elt);
-extern int cons_length(Sxpr obj);
-
-Sxpr sxpr_name(Sxpr obj);
-int sxpr_is(Sxpr obj, char *s);
-int sxpr_elementp(Sxpr obj, Sxpr name);
-Sxpr sxpr_attributes(Sxpr obj);
-Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def);
-Sxpr sxpr_children(Sxpr obj);
-Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def);
-Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def);
-Sxpr sxpr_child0(Sxpr obj, Sxpr def);
-Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def);
-
-/** Create a new atom.
- *
- * @param s atom name
- * @return new atom
- */
-static inline Sxpr mkatom(char *s){
- return atom_new(s);
-}
-
-/** Create a new string sxpr.
- *
- * @param s string bytes (copied)
- * @return new string
- */
-static inline Sxpr mkstring(char *s){
- return string_new(s);
-}
-
-/** Create an integer sxpr.
- *
- * @param i value
- * @return sxpr
- */
-static inline Sxpr mkint(int i){
- return OBJI(T_UINT, i);
-}
-
-/** Create a boolean sxpr.
- *
- * @param b value
- * @return sxpr
- */
-static inline Sxpr mkbool(int b){
- return OBJI(T_BOOL, (b ? 1 : 0));
-}
-
-/* Constants used in parsing and printing. */
-#define k_list_open "("
-#define c_list_open '('
-#define k_list_close ")"
-#define c_list_close ')'
-#define k_true "true"
-#define k_false "false"
-
-#define c_var '$'
-#define c_escape '\\'
-#define c_single_quote '\''
-#define c_double_quote '"'
-#define c_string_open c_double_quote
-#define c_string_close c_double_quote
-#define c_data_open '['
-#define c_data_close ']'
-#define c_binary '*'
-#define c_eval '!'
-#define c_concat_open '{'
-#define c_concat_close '}'
-
-#endif /* ! _XUTIL_SXPR_H_ */
+++ /dev/null
-
-#ifdef __KERNEL__
-# include <linux/config.h>
-# include <linux/module.h>
-# include <linux/kernel.h>
-# include <linux/string.h>
-# include <linux/errno.h>
-#else
-# include <stdlib.h>
-# include <errno.h>
-#endif
-
-#include "iostream.h"
-#include "lexis.h"
-#include "sxpr_parser.h"
-#include "sys_string.h"
-#include "enum.h"
-
-/** @file
- * Sxpr parsing.
- *
- * So that the parser does not leak memory, all sxprs constructed by
- * the parser must be freed on error. On successful parse the sxpr
- * returned becomes the responsibility of the caller.
- *
- * @author Mike Wray <mike.wray@hpl.hp.com>
- */
-
-#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
-#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args)
-
-static void reset(Parser *z);
-static int inputchar(Parser *p, char c);
-static int savechar(Parser *p, char c);
-extern void parse_error(Parser *in);
-extern void parse_error_id(Parser *in, ParseErrorId id);
-
-static int begin_start(Parser *p, char c);
-static int state_start(Parser *p, char c);
-static int end_start(Parser *p);
-
-static int begin_comment(Parser *p, char c);
-static int state_comment(Parser *p, char c);
-static int end_comment(Parser *p);
-
-static int begin_string(Parser *p, char c);
-static int state_string(Parser *p, char c);
-static int end_string(Parser *p);
-static int state_escape(Parser *p, char c);
-static int state_octal(Parser *p, char c);
-static int state_hex(Parser *p, char c);
-
-static int begin_atom(Parser *p, char c);
-static int state_atom(Parser *p, char c);
-static int end_atom(Parser *p);
-
-static int state_list(Parser *p, char c);
-static int begin_list(Parser *p, char c);
-static int end_list(Parser *p);
-
-/** Print a parse error.
- *
- * @param in parser
- * @param msg format followed by printf arguments
- */
-void eprintf(Parser *in, char *msg, ...){
- va_list args;
- if(in->error_out){
- va_start(args, msg);
- IOStream_vprint(in->error_out, msg, args);
- va_end(args);
- }
-}
-
-/** Print a parse warning.
- *
- * @param in parser
- * @param msg format followed by printf arguments
- */
-void wprintf(Parser *in, char *msg, ...){
- va_list args;
- if(in->error_out){
- va_start(args, msg);
- IOStream_vprint(in->error_out, msg, args);
- va_end(args);
- }
-}
-
-/*============================================================================*/
-
-/** Record defining the message for a parse error. */
-typedef struct {
- ParseErrorId id;
- char *message;
-} ParseError;
-
-/** Format for printing parse error messages. */
-#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s"
-
-/** Message catalog for the parse error codes. */
-static ParseError catalog[] = {
- { PARSE_ERR_UNSPECIFIED, "unspecified error" },
- { PARSE_ERR_NOMEM, "out of memory" },
- { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
- { PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
- { PARSE_ERR_INVALID_SYNTAX, "syntax error" },
- { PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
- { 0, NULL }
-};
-
-/** Number of entries in the message catalog. */
-const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
-
-void ParserState_free(ParserState *z){
- if(!z) return;
- objfree(z->val);
- deallocate(z);
-}
-
-int ParserState_new(ParserStateFn *fn, char *name,
- ParserState *parent, ParserState **val){
- int err = 0;
- ParserState *z;
- z = ALLOCATE(ParserState);
- if(z){
- z->name = name;
- z->fn = fn;
- z->parent = parent;
- z->val = ONULL;
- } else {
- err = -ENOMEM;
- }
- if(!err) *val = z;
- return err;
-}
-
-/** Free a parser.
- * No-op if the parser is null.
- *
- * @param z parser
- */
-void Parser_free(Parser *z){
- if(!z) return;
- objfree(z->val);
- z->val = ONONE;
- deallocate(z);
-}
-
-/** Create a new parser. The error stream defaults to null.
- */
-Parser * Parser_new(void){
- Parser *z = ALLOCATE(Parser);
- int err = -ENOMEM;
-
- if(!z) goto exit;
- err = 0;
- reset(z);
- exit:
- if(err){
- Parser_free(z);
- z = NULL;
- }
- return z;
-}
-
-/** Get the next character.
- * Records the character read in the parser,
- * and sets the line and character counts.
- *
- * @param p parser
- * @return error flag: 0 on success, non-zero on error
- */
-static int inputchar(Parser *p, char c){
- int err = 0;
- if(c=='\n'){
- p->line_no++;
- p->char_no = 0;
- } else {
- p->char_no++;
- }
- return err;
-}
-
-static int savechar(Parser *p, char c){
- int err = 0;
- if(p->buf_i >= p->buf_n){
- err = -ENOMEM;
- goto exit;
- }
- p->buf[p->buf_i] = c;
- p->buf_i++;
- exit:
- return err;
-}
-
-int Parser_input_char(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- //skip;
- } else {
- inputchar(p, c);
- }
- if(!p->state){
- err = begin_start(p, c);
- if(err) goto exit;
- }
- err = p->state->fn(p, c);
- exit:
- return err;
-}
-
-int Parser_input_eof(Parser *p){
- int err = 0;
- p->eof = 1;
- err = Parser_input_char(p, IOSTREAM_EOF);
- return err;
-}
-
-int Parser_input(Parser *p, char *buf, int buf_n){
- int err = 0;
- int i = 0;
- if(buf_n <= 0){
- err = Parser_input_eof(p);
- goto exit;
- }
- for(i = 0; i<buf_n; i++){
- err = Parser_input_char(p, buf[i]);
- if(err) goto exit;
- }
- exit:
- err = (err < 0 ? err : buf_n);
- return err;
-}
-
-int Parser_push(Parser *p, ParserStateFn *fn, char *name){
- int err = 0;
- err = ParserState_new(fn, name, p->state, &p->state);
- return err;
-}
-
-int Parser_pop(Parser *p){
- int err = 0;
- ParserState *s = p->state;
- p->state = s->parent;
- ParserState_free(s);
- return err;
-}
-
-int Parser_return(Parser *p){
- int err = 0;
- Sxpr val = ONONE;
- if(!p->state){
- err = -EINVAL;
- goto exit;
- }
- val = p->state->val;
- p->state->val = ONONE;
- err = Parser_pop(p);
- if(err) goto exit;
- if(p->state){
- err = cons_push(&p->state->val, val);
- } else {
- val = nrev(val);
- p->val = val;
- }
- exit:
- if(err){
- objfree(val);
- }
- return err;
-}
-
-/** Determine if a character is a separator.
- *
- * @param p parser
- * @param c character to test
- * @return 1 if a separator, 0 otherwise
- */
-static int is_separator(Parser *p, char c){
- return in_sep_class(c);
-}
-
-/** Return the current token.
- * The return value points at the internal buffer, so
- * it must not be modified (or freed). Use copy_token() if you need a copy.
- *
- * @param p parser
- * @return token
- */
-char *peek_token(Parser *p){
- return p->buf;
-}
-
-/** Return a copy of the current token.
- * The returned value should be freed when finished with.
- *
- * @param p parser
- * @return copy of token
- */
-char *copy_token(Parser *p){
- return strdup(peek_token(p));
-}
-
-static int do_intern(Parser *p){
- int err = 0;
- Sxpr obj = intern(peek_token(p));
- if(NOMEMP(obj)){
- err = -ENOMEM;
- } else {
- p->state->val = obj;
- }
- return err;
-}
-
-static int do_string(Parser *p){
- int err = 0;
- Sxpr obj;
- obj = string_new(peek_token(p));
- if(NOMEMP(obj)){
- err = -ENOMEM;
- } else {
- p->state->val = obj;
- }
- return err;
-}
-
-void newtoken(Parser *p){
- memset(p->buf, 0, p->buf_n);
- p->buf_i = 0;
- p->tok_begin_line = p->line_no;
- p->tok_begin_char = p->char_no;
-}
-
-int get_escape(char c, char *d){
- int err = 0;
- switch(c){
- case 'a': *d = '\a'; break;
- case 'b': *d = '\b'; break;
- case 'f': *d = '\f'; break;
- case 'n': *d = '\n'; break;
- case 'r': *d = '\r'; break;
- case 't': *d = '\t'; break;
- case 'v': *d = '\v'; break;
- case c_escape: *d = c_escape; break;
- case c_single_quote: *d = c_single_quote; break;
- case c_double_quote: *d = c_double_quote; break;
- default:
- err = -EINVAL;
- }
- return err;
-}
-
-int Parser_ready(Parser *p){
- return CONSP(p->val) || (p->start_state && CONSP(p->start_state->val));
-}
-
-Sxpr Parser_get_val(Parser *p){
- Sxpr v = ONONE;
- if(CONSP(p->val)){
- v = CAR(p->val);
- p->val = CDR(p->val);
- } else if (CONSP(p->start_state->val)){
- p->val = p->start_state->val;
- p->val = nrev(p->val);
- p->start_state->val = ONULL;
- v = CAR(p->val);
- p->val = CDR(p->val);
- }
- return v;
-}
-
-Sxpr Parser_get_all(Parser *p){
- Sxpr v = ONULL;
- if(CONSP(p->val)){
- v = p->val;
- p->val = ONONE;
- } else if(CONSP(p->start_state->val)){
- v = p->start_state->val;
- p->start_state->val = ONULL;
- v = nrev(v);
- }
- return v;
-}
-
-int begin_start(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_start, "start");
- if(err) goto exit;
- p->start_state = p->state;
- exit:
- return err;
-}
-
-int state_start(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- err = end_start(p);
- } else if(in_space_class(c)){
- //skip
- } else if(in_comment_class(c)){
- begin_comment(p, c);
- } else if(c == c_list_open){
- begin_list(p, c);
- } else if(c == c_list_close){
- parse_error(p);
- err = -EINVAL;
- } else if(in_string_quote_class(c)){
- begin_string(p, c);
- } else if(in_printable_class(c)){
- begin_atom(p, c);
- } else if(c == 0x04){
- //ctrl-D, EOT: end-of-text.
- Parser_input_eof(p);
- } else {
- parse_error(p);
- err = -EINVAL;
- }
- return err;
-}
-
-int end_start(Parser *p){
- int err = 0;
- err = Parser_return(p);
- return err;
-}
-
-int begin_comment(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_comment, "comment");
- if(err) goto exit;
- err = inputchar(p, c);
- exit:
- return err;
-}
-
-int state_comment(Parser *p, char c){
- int err = 0;
- if(c == '\n' || at_eof(p)){
- err = end_comment(p);
- } else {
- err = inputchar(p, c);
- }
- return err;
-}
-
-int end_comment(Parser *p){
- return Parser_pop(p);
-}
-
-int begin_string(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_string, "string");
- if(err) goto exit;
- newtoken(p);
- p->state->delim = c;
- exit:
- return err;
-}
-
-int state_string(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- } else if(c == p->state->delim){
- err = end_string(p);
- } else if(c == '\\'){
- err = Parser_push(p, state_escape, "escape");
- } else {
- err = savechar(p, c);
- }
- return err;
-}
-
-int end_string(Parser *p){
- int err = 0;
- err = do_string(p);
- if(err) goto exit;
- err = Parser_return(p);
- exit:
- return err;
-}
-
-int state_escape(Parser *p, char c){
- int err = 0;
- char d;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- goto exit;
- }
- if(get_escape(c, &d) == 0){
- err = savechar(p, d);
- if(err) goto exit;
- err = Parser_pop(p);
- } else if(c == 'x'){
- p->state->fn = state_hex;
- p->state->ival = 0;
- p->state->count = 0;
- } else {
- p->state->fn = state_octal;
- p->state->ival = 0;
- p->state->count = 0;
- err = Parser_input_char(p, c);
- }
- exit:
- return err;
-}
-
-int octaldone(Parser *p){
- int err = 0;
- char d = (char)(p->state->ival & 0xff);
- err = Parser_pop(p);
- if(err) goto exit;
- err = Parser_input_char(p, d);
- exit:
- return err;
-}
-
-int octaldigit(Parser *p, char c){
- int err = 0;
- p->state->ival *= 8;
- p->state->ival += c - '0';
- p->state->count++;
- if(err) goto exit;
- if(p->state->ival < 0 || p->state->ival > 0xff){
- parse_error(p);
- err = -EINVAL;
- goto exit;
- }
- if(p->state->count == 3){
- err = octaldone(p);
- }
- exit:
- return err;
-}
-
-int state_octal(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- goto exit;
- } else if('0' <= c && c <= '7'){
- err = octaldigit(p, c);
- } else {
- err = octaldone(p);
- if(err) goto exit;
- Parser_input_char(p, c);
- }
- exit:
- return err;
-}
-
-int hexdone(Parser *p){
- int err = 0;
- char d = (char)(p->state->ival & 0xff);
- err = Parser_pop(p);
- if(err) goto exit;
- err = Parser_input_char(p, d);
- exit:
- return err;
-}
-
-int hexdigit(Parser *p, char c, char d){
- int err = 0;
- p->state->ival *= 16;
- p->state->ival += c - d;
- p->state->count++;
- if(err) goto exit;
- if(p->state->ival < 0 || p->state->ival > 0xff){
- parse_error(p);
- err = -EINVAL;
- goto exit;
- }
- if(p->state->count == 2){
- err = hexdone(p);
- }
- exit:
- return err;
-}
-
-int state_hex(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- goto exit;
- } else if('0' <= c && c <= '9'){
- err = hexdigit(p, c, '0');
- } else if('A' <= c && c <= 'F'){
- err = hexdigit(p, c, 'A');
- } else if('a' <= c && c <= 'f'){
- err = hexdigit(p, c, 'a');
- } else if(p->state->count){
- err =hexdone(p);
- if(err) goto exit;
- Parser_input_char(p, c);
- }
- exit:
- return err;
-}
-
-int begin_atom(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_atom, "atom");
- if(err) goto exit;
- newtoken(p);
- err = savechar(p, c);
- exit:
- return err;
-}
-
-int state_atom(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- err = end_atom(p);
- } else if(is_separator(p, c) ||
- in_space_class(c) ||
- in_comment_class(c)){
- err = end_atom(p);
- if(err) goto exit;
- err = Parser_input_char(p, c);
- } else {
- err = savechar(p, c);
- }
- exit:
- return err;
-}
-
-int end_atom(Parser *p){
- int err = 0;
- err = do_intern(p);
- if(err) goto exit;
- err = Parser_return(p);
- exit:
- return err;
-}
-
-int state_list(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- } else if(c == c_list_close){
- p->state->val = nrev(p->state->val);
- err = end_list(p);
- } else {
- err = state_start(p, c);
- }
- return err;
-
-}
-
-int begin_list(Parser *p, char c){
- return Parser_push(p, state_list, "list");
-}
-
-int end_list(Parser *p){
- return Parser_return(p);
-}
-
-/** Reset the fields of a parser to initial values.
- *
- * @param z parser
- */
-static void reset(Parser *z){
- IOStream *error_out = z->error_out;
- int flags = z->flags;
- memzero(z, sizeof(Parser));
- z->buf_n = sizeof(z->buf) - 1;
- z->buf_i = 0;
- z->line_no = 1;
- z->char_no = 0;
- z->error_out = error_out;
- z->flags = flags;
-}
-
-/** Set the parser error stream.
- * Parse errors are reported on the the error stream if it is non-null.
- *
- * @param z parser
- * @param error_out error stream
- */
-void set_error_stream(Parser *z, IOStream *error_out){
- if(z){
- z->error_out = error_out;
- }
-}
-
-/** Get the parser error message for an error code.
- *
- * @param id error code
- * @return error message (empty string if the code is unknown)
- */
-static char *get_message(ParseErrorId id){
- int i;
- for(i=0; i<catalog_n; i++){
- if(id == catalog[i].id){
- return catalog[i].message;
- }
- }
- return "";
-}
-
-/** Get the line number.
- *
- * @param in parser
- */
-int get_line(Parser *in){
- return in->line_no;
-}
-
-/** Get the column number.
- *
- * @param in parser
- */
-int get_column(Parser *in){
- return in->char_no;
-}
-
-/** Get the line number the current token started on.
- *
- * @param in parser
- */
-int get_tok_line(Parser *in){
- return in->tok_begin_line;
-}
-
-/** Get the column number the current token started on.
- *
- * @param in parser
- */
-int get_tok_column(Parser *in){
- return in->tok_begin_char;
-}
-
-/** Report a parse error.
- * Does nothing if the error stream is null or there is no error.
- *
- * @param in parser
- */
-static void report_error(Parser *in){
- if(in->error_out && in->err){
- char *msg = get_message(in->err);
- char *tok = peek_token(in);
- IOStream_print(in->error_out, PARSE_ERR_FMT,
- get_tok_line(in), get_tok_column(in), msg);
- if(tok && tok[0]){
- IOStream_print(in->error_out, " '%s'", tok);
- }
- IOStream_print(in->error_out, "\n");
- }
-}
-
-/** Get the error message for the current parse error code.
- * Does nothing if there is no error.
- *
- * @param in parser
- * @param buf where to place the message
- * @param n maximum number of characters to place in buf
- * @return current error code (zero for no error)
- */
-int parse_error_message(Parser *in, char *buf, int n){
- if(in->err){
- char *msg = get_message(in->err);
- snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg);
- }
- return in->err;
-}
-
-/** Flag an unspecified parse error. All subsequent reads will fail.
- *
- * @param in parser
- */
-void parse_error(Parser *in){
- parse_error_id(in, PARSE_ERR_INVALID_SYNTAX);
-}
-
-/** Flag a parse error. All subsequent reads will fail.
- * Does not change the parser error code if it is already set.
- *
- * @param in parser
- * @param id error code
- */
-void parse_error_id(Parser *in, ParseErrorId id){
- if(!in->err){
- in->err = id;
- report_error(in);
- }
-}
-
-/** Test if the parser's error flag is set.
- *
- * @param in parser
- * @return 1 if set, 0 otherwise
- */
-int has_error(Parser *in){
- return (in->err > 0);
-}
-
-/** Test if the parser is at end of input.
- *
- * @param in parser
- * @return 1 if at EOF, 0 otherwise
- */
-int at_eof(Parser *p){
- return p->eof;
-}
-
-//#define SXPR_PARSER_MAIN
-#ifdef SXPR_PARSER_MAIN
-/* Stuff for standalone testing. */
-
-#include "file_stream.h"
-#include "string_stream.h"
-
-int stringof(Sxpr exp, char **s){
- int err = 0;
- if(ATOMP(exp)){
- *s = atom_name(exp);
- } else if(STRINGP(exp)){
- *s = string_string(exp);
- } else {
- err = -EINVAL;
- *s = NULL;
- }
- return err;
-}
-
-int child_string(Sxpr exp, Sxpr key, char **s){
- int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = stringof(val, s);
- return err;
-}
-
-int intof(Sxpr exp, int *v){
- int err = 0;
- char *s;
- unsigned long l;
- if(INTP(exp)){
- *v = OBJ_INT(exp);
- } else {
- err = stringof(exp, &s);
- if(err) goto exit;
- err = convert_atoul(s, &l);
- *v = (int)l;
- }
- exit:
- return err;
-}
-
-int child_int(Sxpr exp, Sxpr key, int *v){
- int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = intof(val, v);
- return err;
-}
-
-int eval_vnet(Sxpr exp){
- int err = 0;
- Sxpr oid = intern("id");
- int id;
- err = child_int(exp, oid, &id);
- if(err) goto exit;
- dprintf("> vnet id=%d\n", id);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int eval_connect(Sxpr exp){
- int err = 0;
- Sxpr ovif = intern("vif");
- Sxpr ovnet = intern("vnet");
- char *vif;
- int vnet;
-
- err = child_string(exp, ovif, &vif);
- if(err) goto exit;
- err = child_int(exp, ovnet, &vnet);
- if(err) goto exit;
- dprintf("> connect vif=%s vnet=%d\n", vif, vnet);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int eval(Sxpr exp){
- int err = 0;
- Sxpr oconnect = intern("connect");
- Sxpr ovnet = intern("vnet");
-
- if(sxpr_elementp(exp, ovnet)){
- err = eval_vnet(exp);
- } else if(sxpr_elementp(exp, oconnect)){
- err = eval_connect(exp);
- } else {
- err = -EINVAL;
- }
- return err;
-}
-
-/** Main program for testing.
- * Parses input and prints it.
- *
- * @param argc number of arguments
- * @param argv arguments
- * @return error code
- */
-int main(int argc, char *argv[]){
- Parser *pin;
- int err = 0;
- char buf[1024];
- int k;
- Sxpr obj;
- //Sxpr l, x;
- int i = 0;
-
- pin = Parser_new();
- set_error_stream(pin, iostdout);
- dprintf("> parse...\n");
- while(1){
- k = fread(buf, 1, 1, stdin);
- err = Parser_input(pin, buf, k);
- while(Parser_ready(pin)){
- obj = Parser_get_val(pin);
- printf("obj %d\n", i++);
- objprint(iostdout, obj, 0); printf("\n");
- }
- if(k <= 0) break;
- }
-/* obj = Parser_get_all(pin); */
-/* for(l = obj ; CONSP(l); l = CDR(l)){ */
-/* x = CAR(l); */
-/* objprint(iostdout, x, 0); printf("\n"); */
-/* eval(x); */
-/* } */
- dprintf("> err=%d\n", err);
- return 0;
-}
-#endif
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_SXPR_PARSER_H_
-#define _XUTIL_SXPR_PARSER_H_
-
-#include "sxpr.h"
-#include "iostream.h"
-
-/** @file
- * Sxpr parsing definitions.
- */
-
-/** Size of a parser input buffer.
- * Tokens read must fit into this size (including trailing null).
- */
-#define PARSER_BUF_SIZE 1024
-
-struct Parser;
-typedef int ParserStateFn(struct Parser *, char c);
-
-typedef struct ParserState {
- struct ParserState *parent;
- Sxpr val;
- int ival;
- int count;
- char delim;
- ParserStateFn *fn;
- char *name;
-} ParserState;
-
-/** Structure representing an input source for the parser.
- * Can read from any IOStream implementation.
- */
-typedef struct Parser {
- Sxpr val;
- /** Error reporting stream (null for no reports). */
- IOStream *error_out;
- int eof;
- /** Error flag. Non-zero if there has been a read error. */
- int err;
- /** Line number on input (from 1). */
- int line_no;
- /** Column number of input (reset on new line). */
- int char_no;
- /** Lookahead character. */
- char c;
- /** Buffer for reading tokens. */
- char buf[PARSER_BUF_SIZE];
- /** Size of token buffer. */
- int buf_n;
- int buf_i;
- /** Line the last token started on. */
- int tok_begin_line;
- /** Character number the last token started on. */
- int tok_begin_char;
- /** Parsing flags. */
- int flags;
- ParserState *state;
- ParserState *start_state;
-} Parser;
-
-/** Parser error codes. */
-typedef enum {
- PARSE_ERR_NONE=0,
- PARSE_ERR_UNSPECIFIED,
- PARSE_ERR_NOMEM,
- PARSE_ERR_UNEXPECTED_EOF,
- PARSE_ERR_TOKEN_TOO_LONG,
- PARSE_ERR_INVALID_SYNTAX,
- PARSE_ERR_INVALID_ESCAPE,
-} ParseErrorId;
-
-
-/** Parser flags. */
-//enum {
-//};
-
-/** Raise some parser flags.
- *
- * @param in parser
- * @param flags flags mask
- */
-inline static void parser_flags_raise(Parser *in, int flags){
- in->flags |= flags;
-}
-
-/** Lower some parser flags.
- *
- * @param in parser
- * @param flags flags mask
- */
-inline static void parser_flags_lower(Parser *in, int flags){
- in->flags &= ~flags;
-}
-
-/** Clear all parser flags.
- *
- * @param in parser
- */
-inline static void parser_flags_clear(Parser *in){
- in->flags = 0;
-}
-
-extern void Parser_free(Parser *z);
-extern Parser * Parser_new(void);
-extern int Parser_input(Parser *p, char *buf, int buf_n);
-extern int Parser_input_eof(Parser *p);
-extern int Parser_input_char(Parser *p, char c);
-extern void set_error_stream(Parser *z, IOStream *error_out);
-
-extern int parse_error_message(Parser *in, char *buf, int n);
-extern int has_error(Parser *in);
-extern int at_eof(Parser *in);
-
-int Parser_ready(Parser *p);
-Sxpr Parser_get_val(Parser *p);
-Sxpr Parser_get_all(Parser *p);
-
-#endif /* ! _XUTIL_SXPR_PARSER_H_ */